一、关于对象
关于菱形继承对象的内存分布,可以查看C++菱形继承内存布局分析了解。
二、构造函数语义学
四种情况下,编译器会为未声明 contructor 的 class 合成一个 default constructor。
带有 Default Constructor 的 Member Class Object
如果一个 class 没有任何的 constructor, 但是它含有一个拥有 default constructor 的 member object,那么这个 class 的 implicit default constructor 就是 nontrivial,编译器需要为此 class 合成一个 default constructor。此 class 的 default constructor 会调用每个 member object 的 default constructor。
带有 Default Constructor 的 Base Class
类似的道理,一个没有任何 constructor 的 class 派生自一个带有 default constructor 的 base class,这个 derived class 的 default constructor 会被视为 nontrivial,并需要被合成出来。它将调用上一层 base class 的 default constructor (根据它们的声明次序)。对这个 derived class 来说,合成出来的 constructor 和一个明确提供的 default constructor 一样。
带有一个Virtual Function 的 Class
另外两种情况,也需要合成出 default constructor:
- class 声明(或继承)一个 virtual function。
- class 派生自一个继承串链,其中有一个或更多的 virtual base classes。
带有一个 Virtual Base Class 的 Class
这些合成的 constructor 叫 implicit nontrivial default constructor。不满足上面四种情况且没有声明任何 constructor 的 class, 他们的 constructor 叫 implicit trivial default constructor,编译不会为这些 class 合成 constructor。
在合成的 default constructor 中,只有 base class subojects 和 member class objects 会被初始化。所有其他的 nonstatic data member,如整数、整数指针、整数数组等都不会被初始化。
和 default constructor 一样,如果 class 没有声明一个 copy constructor,编译器就会隐式的声明(implicitly declared)或隐式的定义(implicitly defined)一个。copy constructor 也分为 trivial 和 nontrivial 两种。只有 nontrivial 的实体才会被合成于程序中。决定一个 copy constructor 是否为 trivial 的标准在于 class 是否展现出所谓的”bitwise copy semantic”。
四种情况下,class 不展现出”bitwise copy semantic”。
当 class 内含一个 member object 而后者的 class 声明中有一个 copy constructor。
当 class 继承自一个 base class 而后者存在有一个 copy constructor 时(不能是被明确声明或是被合成而得)。
当 class 声明一个或多个 virtual functions 时。
当 class 派生自一个继承串链,其中有一个或多个 virtual base classes 时。
三、Data 语意学
上古时期,下面代码中,类A的成员函数返回的是全局x,而不是成员变量x。这个问题已经修复了,现在总数返回成员变量x。
int x; struct A { int Func() { return x; } int x; };
下面的代码中,val_t的类型是使用全局的val_t的定义,即x,而不是类中声明的val_t,所以需注意。
using val_t = int; struct A { void FuncA(val_t v) { printf("sizeof(val_t) = %d\n", sizeof(v)); // = sizeof(int) = 4 } using val_t = char; void FuncB(val_t v) { printf("sizeof(val_t) = %d\n", sizeof(v)); // = sizeof(char) = 1 } }; int main(int argc, char** argv) { A a; a.FuncA(0); a.FuncB(0); return 0; }
运行结果
sizeof(val_t) = 4 sizeof(val_t) = 1