《深度探索c++内存模型》读书笔记 (二)
发表时间:2020-10-19
发布人:葵宇科技
浏览次数:23
文┞仿目次
- 媒介
- 默认构造函数
- 带有默认构造函数的类对象成员
- 带默认构造函数的基类
- 带有虚函数的类
- 总结
媒介
c++ 编译器会在人意想不到的处所做一些隐式操作。例如,只含有一个参数的构造函数,会被当做类型转换运算符。而关键字explict就是为了阻拦这一机制。
默认构造函数
c++ 编译器会在须要的时刻主动生成默认构造函数。
带有默认构造函数的类对象成员
如不雅一个类没有任何的构造函数,然则它有一个对象成员,这个对象成员有一个默认构造函数。那么编译器将会为这个类生成一个默认构造函数。然则这个生成的机会会是在这个类被调用的时刻。
如不雅有两个文件中都调用了这个类,那么默认构造函数将可能会被生成两次。若何避免这种冲突呢?解决办法是把合成的构造函数内联(inline, 一个内联函数有静态链接 static linkage)。如不雅构造函数太复杂,不合适内联,那么就汇合成一个显式的非内联静态实体(explicit noinline static)。
例如:
class Foo {
public:
Foo()
};
class Bar {
Foo foo;
char *str;
};
// 编译器将会为Bar合成默认构造函数,初始化foo成员。然则并不会初始化str成员!!!
如不雅一个类Foo有本身定义的构造函数(默认的,或者带有参数的),并且这个类还有一个或者多个类成员。那么编译器将会包管这些类成员的构造函数在Foo的构造函数中至少被调用一次。这些成员的构冒昧序与它们在class中的声明次序一致。
带默认构造函数的基类
类似的,如不雅一个没有构造函数的派生类持续自一个带有默认构造函数的基类。那么编译器将会为这个派生类生成默认构造函数。在这个生成的构造函数中按照声明的次序调用基类的构造函数。
如不雅派生类有构造函数,然则没有默认构造函数。编译器将会为现有的构造函数中安插调用基类构造函数的代码,然则并不会生成一个新的默认构造函数。
如不雅这个派生类同时有类成员(这些类成员有默认构造函数)。那么编译器将会在基类构造函数的代码后面安插调用数据成员构造函数的代码。
带有虚函数的类
有以下两种情况会生成默认构造函数
- 类声明或者持续一个虚函数
- 类派生自一个持续串链,个中有一个或者更多的虚基类(virtual base class)
在编译时代,编译器会做两件工作:
- 生成一个虚函数表
- 为每一个对象添加一个额外的虚函数表指针。
对于类所定义的每一个构造函数,编译器将会安插一些代码,为虚表指针赋初值。带有一个虚基类的类编译器会矢荷琐虚基类在派生类中的地位 在履行时代所决定??
例如
class X{public: int i};
class A :public virtual X {public: int j;};
class B :public virtual X {public: double d;};
class C :public A, public B {public: int k;};
?
// 无法在编译时代决定i的地位(偏移?)
void foo(const A *pa) {
pa->i = 1024;
}
?
int main ()
{
foo (new C);
foo (new A);
...
}
编译器的一种可能的实现方法为:
在每一个派生类的虚基类中安插一个指针。经由引用或者指帐攀来存取一个虚基类的功能都可以由这个指帐攀来实现。
例如:
// 可能的转换操作
void foo(const A *pa) {
pa->__vbcX->i = 1024;
}
总结
在编译器合成的默认构造函数中,会为那些有默认构造函数的成员或者基类调用其默认构造函数。而那些其他的风静态数据成员,例如整数,指针等都不会被初始化,须要类的设计者(就是法度榜样员了)来做这些操作。
新手一般会有两个误会:
- 任何类如不雅没有定义默认构造函数,那么就会被合成出一个来。
- 编译器合成的默认构造函数会明白设置览鲂的每一个数据成员初始值。
这两个没有一个是真的!!!