11.4 Class members
member-declaration member-specificationopt
access-specifier : member-specificationopt
member-declaration:
attribute-specifier-seqopt
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
access-specifier :
virt-specifier:
pure-specifier:
11.4.3 Special member functions
默认构造函数([class.default.ctor])、拷贝构造函数、移动构造函数([class.copy.ctor])、拷贝赋值运算符、移动赋值运算符([class.copy.assign]),以及预期析构函数([class.dtor]),统称为特殊成员函数(special member functions)。
【注释:当程序未显式声明这些成员函数时,实现会为某些类类型隐式地声明它们。如果这些函数被odr-used([basic.def.odr]),或在常量求值([expr.const])中需要,实现将隐式定义它们。 ——注释结束】
隐式声明的特殊成员函数在class-specifier的}处(类定义结束)被声明。程序不得显式定义这些隐式声明的特殊成员函数。
Paw5zx个人理解:点击查看更多
程序不得显式定义这些隐式声明的特殊成员函数。
如果某个特殊成员函数已经被编译器隐式声明,则用户不可以手动定义这些函数
1 | struct A |
可用的(eligible)特殊成员函数是满足以下条件的特殊成员函数:
(6.1) 未被定义为
delete;(6.2) 其关联的约束条件(若存在)([temp.constr])已被满足,并且;
(6.3) 不存在约束更强([temp.constr.order])的同类(
same kind)特殊成员函数。
Paw5zx个人理解:点击查看更多
(6.2) (6.3)都是对模板类的约束。对普通非模板类而言,可用的特殊成员函数等价于非delete的特殊成员函数。
11.4.4 Constructors
11.4.4.1 Default constructors
若一个默认构造函数不是用户提供的,并且同时满足以下条件,则其是平凡的:
- (3.1) 其所属的类没有虚函数([class.virtual])且没有虚基类([class.mi]);
- (3.2) 其所属类的任意非静态数据成员都没有默认成员初始化器([class.mem]);
- (3.3) 其所属类的所有直接基类的默认构造函数都是平凡的;
- (3.4) 对于其所属类的每个类类型(或类类型数组)非静态数据成员,该成员的类型要具有平凡的默认构造函数。
否则默认构造函数是不平凡的。
11.4.4.2 Copy/move constructors
若类X的拷贝/移动构造函数不是用户提供的,并且同时满足以下条件,则其是平凡的:
- (11.1) 类X没有虚函数([class.virtual])且没有虚基类([class.mi]);并且
- (11.2) 用于拷贝/移动每个直接基类子对象的构造函数都是平凡的;并且
- (11.3) 对于X的每个类类型(或类类型数组)非静态数据成员,用于拷贝、移动该成员的构造函数都是平凡的;
否则拷贝/移动构造函数是不平凡的。
11.4.9 Bit-fields
可选的属性说明序列(`attribute-specifier-seq`)作用于被声明的实体。位域不能是静态成员。位域必须是整型或枚举类型;位域的语义属性不属于类成员类型的组成部分。常量表达式(constant-expression)应为一个大于等于零的整型常量表达式,称为位域的宽度。如果位域的宽度大于其类型(或,对于枚举类型,宽度大于其底层类型)的宽度,超出的比特是填充位(参见[[basic.types]]())。类对象内位域的分配规则由实现定义。位域的对齐规则由实现定义。位域会被打包到某个可寻址的分配单元中。
【注:在某些机器上,位域可能跨越多个分配单元,而在另一些机器上则不会。在某些机器上,位域自右向左分配,而在另一些机器上,自左向右分配。——注释结束】
【注:未命名位域常用于填充,以符合外部强加的布局要求。——注释结束】
作为一种特殊情况,若未命名位域的宽度为0,则表示要求下一个位域必须在分配单元的边界上开始对齐。只有在声明未命名位域时,宽度才可以为0。
Paw5zx个人理解:点击查看更多
分配单元是根据位域声明的底层类型而定的,对于上述未命名位域,有以下示例:
1 | struct S |
【注:如果`const T&`类型的引用的初始化器是一个指向位域的左值,则该引用会绑定到一个用该位域的值初始化的临时对象上;而不是直接绑定到该位域。参见[[dcl.init.ref]]()。
Paw5zx个人理解:点击查看更多
位域只占用某几个bit,所以不能按字节寻址,所以无法取地址。因此编译器会生成一个临时对象,把位域的值拷贝进去,然后让const T&引用这个临时对象。
1 | struct S |
如果将`true`或`false`存储到一个任意大小的类型为bool的位域中(包括1位的位域),那么原始的布尔值与位域中的值在比较时相等。
如果一个枚举类型的值被存储到相同类型的位域中,且该位域的宽度足以容纳该枚举类型的所有值([[dcl.enum]]()),那么原始值与位域中的值在比较时相等。
【示例:
1 | enum BOOL { FALSE=0, TRUE=1 }; |
Paw5zx个人理解:点击查看更多
整形:存到位域中,超出位域宽度的部分被截断
1 | struct S |
bool型:无论bool位域的大小是多少,存储true或false时,比较结果与原值相等。
1 | struct S |
枚举类型:如果枚举值存入相同枚举类型的位域,且位域宽度足够容纳该枚举的所有可能值,那么存储与比较结果相等
1 | // Color的底层是unsigned int |