C++-----深度探索对象模型-第二章-构造函数语义学(一)

1、C++编译器会做很多你不知道的事,比如构造函数的隐式转换,但是可以添加explic关键字用来制止单一参数的构造函数被当作一个转换运算符。

2、当编译器需要一个默认构造函数的时候,被合成出来的构造函数只执行编译器所需的行动。下面四种情况,必须为class合成一个构造函数。

    1)当一个class没有任何构造函数,但是其内部含有一个类对象,且后者有一个默认构造函数,就必须为该类合成一个构造函数,不过这个合成只有在真正调用的时候才会发生。被合成的默认构造函数只满足编译器的需要,而不是程序员的需要。如果一个class A含有一个或一个以上的类对象,那么class A的每一个construct必须调用每一个类对象的默认构造函数。如果含有多个类对象,编译器会默认按照顺序使调用默认构造函数。

    2)当一个类没有构造函数时,并且这个类派生自一个有默认构造函数的基类,那么这个类的默认构造函数会被合成出来,也就是调用上一层的基类的默认构造函数。

    3)当一个类没有任何构造函数,且该类声明或继承了一个虚函数。或者这个类派生自一个继承串链,其中有一个或更多的虚基类,编译器会合成默认构造函数。这种情况下,编译器做的扩张行为有:产生一个虚函数表,里面存放类的虚函数地址,在每一个类对象中合成一个虚函数指针,指向虚函数表的位置。也就是说,对于那些没没有声明任何构造函数的类,编译器会为他们合成一个默认构造函数,一边正确的初始化每一个类对象的虚函数指针。

    4)当一个类没有任何构造函数,且该类继承自一个虚基类,编译器会为这个类自动合成一个默认构造函数,这些构造函数会安插一些代码,允许每一个虚基类执行期存取操作得以实现。

3、合成的构造函数之所以被合成出来是因为有其自身的任务,比如调用成员对象或者基类的默认构造函数,为每一个类对象初始化其虚函数指针或其虚基类机制。

4、除去上面四种情况,编译器不会合成默认构造函数。也就是C++新手常见的两个误解(1、任何class如果没有定义默认构造函数编译器就会合成。2、编译器合成的默认构造函数会显式设定class内每一个data member的默认值),这两种见解都是错误的。

5、在合成的默认构造函数中,只有基类对象和成员对象会被初始化,其他的非静态成员数据都不会被初始化,包括整数、整数指针、整数数组等,这是编译器不需要的操作。

6、一般有三种情况需要拷贝构造函数:

    1)显式的以一个object的内容作为另一个类对象的初值如下:

class X{
...
};

X x;
X xx=x;

    2)以一个object作为函数的参数,foo(xx)。

    3)当函数返回一个class object时,return xx

7、如果一个类没有显示的定义拷贝构造函数,当类对象以另一个对象作为初始值时,内部是默认逐项初始化手法完成的,也就是把每一个内建的或派生的数据成员,从一个对象拷贝一份到另一个对象身上。对其中的类成员不会拷贝,而是以递归的方式施行逐项初始化。

8、默认构造函数和拷贝构造函数在必要的时候才会由编译器产生出来。

9、和缺省构造函数一样,如果class没有声明一个拷贝构造函数,就会有隐式的声明或隐式的定义出现,和以前一样,会把拷贝构造函数区分为trivial和nontrivial两种,只有nontrivial的实例才会被合成与程序中,决定一个拷贝构造函数是否为trivial的标准在于class是否展现出所谓的位逐次拷贝。

10、当一个类展现出位逐次拷贝时,则不需要编译器合成默认拷贝构造函数。

11、以下四种情况,类不会展现出位逐次拷贝特性:

    1)当class内含有一个成员对象而后者的类声明有一个拷贝构造函数(不论是被class设计者显式的声明,还是被编译器合成)。

    2)当class继承自一个base class而后者存在一个拷贝构造函数,也不管是显式声明还是合成。

    3)当class声明了一个或多个虚函数

    4)当class派生自一个继承串链,其中有一个或多个虚基类。

    可以看出,这四种情况和上面的构造函数的情况很像,出现上面四种情况时,如果没有声明任何构造函数,编译器会合成一个默认构造函数,出现上面四种情况,如果没有声明拷贝构造函数编译器也会合成一个默认拷贝构造函数。如果没有出现上面几种情况,不会生成默认构造函数,也不会生成默认拷贝构造函数,会利用位逐次拷贝来进行拷贝。

12、编译期间两个程序扩张操作(只要有一个class声明一个或多个虚函数)

    1)增加一个虚函数表,内含每一个有作用的虚函数的地址。

    2)一个指向虚函数表的指针,安插在每一个类对象内。

13、位逐次拷贝其实是一种浅拷贝,也就是拷贝的指针指向的是同一块内存,当释放了一个指针的内存时,另一个指针会指向为空,造成很大的bug。其中当有了虚函数机制时,就有了vptr,对vptr的浅拷贝显然是不正确的,因为它可能会指向错误的虚函数表,这也就解释了为什么有了虚函数就需要合成的拷贝构造函数来对vptr进行正确的初始化。

14、如果以一个派生类为基类对象赋值,那么简单的位逐次拷贝将会出现一个问题,也就是,会将基类的虚函数指针指向派生类的虚函数表,这显然是不正确,在这种情况下,编译器合成拷贝构造函数,安插一些代码以设定虚基类指针或偏移量,对每一个成员执行必要的成员逐次拷贝。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值