C++对象模型之第二章——构造函数语义学

来源:互联网 发布:java api手机中文版 编辑:程序博客网 时间:2024/06/01 15:24

一、构造函数

编译器会合成4个隐性的非无用的构造函数的情况:

1.含有带有默认构造函数的成员类的对象。

这个合成构造函数只有被真正使用时,才会被合成。这时有一个问题产生,即在多个不同的编译块产生都各自每个的合成构造函数。如何避免多个默认构造函数产生,将合成的默认、拷贝、析构、赋值拷贝以inline方式完成。
  如果,类成员有多的,编译器不管该类有没有默认构造函数,都会调用每个成员的默认构造函数,会扩张现有的构造。不会另外生成新的默认构造函数。其调用各自构造器的顺序与声明顺序一致。

2.带有默认函数的基类

  如果一个没有任何构造函数的类派生自一个有默认构造函数的基类,则这个编译器生成的构造函数也是非无用。编译器会扩充现有的每个构造函数。不会另外生成新的默认构造函数。

3.带有虚函数的类

  a.class声明或继承一个虚函数。

  在此种情况,为了保证多态机制的完成。一般,编译器会自动的为基类对象和其派生类的vptr设置初值,来放置虚表的地址。至于没有声明任何默认构造函数的类,编译器会生成,一个非无用的默认构造,来确保每一个类的vptr正确初始化。

  b.class派生一个继承链,有一个或多于一个虚基类。

4.带有虚基类的类


 原书中的例子,类X,A,B,C存在以下关系:


  这时,foo函数的参数为基类A类型的指针,在看看main里面,foo函数调用了两次,由于泛型和多态的原因,编译器无法得到X::i的实际位置。因为pa的类型是不固定的,编译器必须使用延时的代码段,将pa的类型和i的读取重原来的编译期延时到运行期。派生类通过一个指针指向每一个虚基类。foo实际单用过程如下:


      _vbcX表示编译器在构造期间完成的, 对于每一个存在虚继承类的构造函数,如果类没有默认构造函数,编译器会安插那些代码段。这时,编译器生成的构造函数是非无用的。




c++新手的两大误解:

1.任何没有定义默认构造函数,就会有编译器生成一个。(只有该类没有构造函数,才会合成一个默认构造函数。其实有时候,不是重新生成,而是扩充现有。以上4中情况)

2.编译器合成的默认构造函数,会初始化类中,每一个数据成员的默认值。

二、拷贝构造

1 .按成员拷贝

当一个类没有明确的拷贝构造函数,这时编译器会合成一个拷贝构造函数。这个拷贝函数是安成员进行复制的,如书中的例子:

如果一个string类对象呗声明为其他类的成员,如word类
会先拷贝_occers成员,然后安成员拷贝 _word成员。

2 .按位拷贝


3.编译器合成拷贝构造函数不是按位拷贝的4中情况(也就是生成的拷贝函数是非无用的):

   1.类内部含有拷贝函数的对象成员(无论是定义的还是编译器合成的)时。
   2.类的父类具有拷贝构造函数(无论是定义的还是编译器合成的)
   3.类内部有一个或多个虚函数时
   4.类派生自继承 串链。

      前两种情况不必多说,主要看后两种情况。
  第三种情况需要重新设定虚表指针:
    由于一个具有虚函数的类内部,有一个虚表指针,指向在编译期间生成虚函数表。当类的导入vptr到类中,类就不再展现按位拷贝的特性了。

三、程序转化语义学

1.明确的初始化
当连续的定义多个对象,对象的初始化会被剔除,在结束定义后,插入构造函数实现初始化。
定义对象x1, x2, X3 的过程如下:
被编译器转换后的古城如下:

2.参数的初始化
3.返回值的初始化

四、成员们的初始化列表

与c++ primer中 提到的一样,必须以列表形式初始化的成员有:
1.成员变量为引用。
2.成员带有const属性。
3.基类构造函数具有一组参数。
4.成员类对象的构造函数具有一组参数。
并且他们的初始化顺序只与声明顺序有关,与列表的顺序无关。这里可能的顺序,可能出现程序的漏洞,g++ gdn c++编译器6等编译器发出警告。


1 0
原创粉丝点击