《深度探索C++对象模型》—— 构造函数篇

一、Default constructor 建构操作

1、Default constructor函数只会在编译器需要的时候才会自动创建,有如下四种情况

  a、“带有Default constructor”的Menber Class Object(I、自动创建;II、如果class中游Default constructor,但是没有对Member Class Object进行初始化,Class会自动对构造函数进行扩张,调用Member Class Object的Default constructor;III、如果有多个Member Class Object的话,根据声明次序依次调用)

  b、“带有Default constructor”的Base Class

  c、“带有一个Virtual Function”的class(主要是因为要初始化指向虚函数表的指针)

  d、“带有一个Virtual Base Class”的Class(需要通过某些操作实现Base Class在Derived Class的实际偏移地址)

2、两个容易混淆的观点:

  a、 一个Class,如果没有定义default constructor ,编译器不一定会自动生成一个constructor

  b、编译器合成出来的default constructor不会对每一个data member进行初始化

二、Copy constructor 建构操作

1、三种有可能调用Copy constructor的情况

  a、Class X{};    X x; X xx=x;

  b、extern void foo(X xx); void bar(){X xx; foo(xx);}

  c、X foo(){X xx;   return xx;}

2、如果用户没有定义Copy constructor,那么Copy constructor函数只会在编译器需要的时候才会自动创建,有如下四种情况

  a、“带有Copy constructor”的Menber Class Object

  b、“带有Copyt constructor”的Base Class

  c、“带有一个Virtual Function”的class(主要是因为要初始化指向虚函数表的指针)

  d、“带有一个Virtual Base Class”的Class(需要通过某些操作实现Base Class在Derived Class的实际偏移地址)

   说明:当编译器不合成Copy constructor时,编译器会采用MemberWise 手法来进行成员变量的复赋值

3、重新设定virtual table:

  a、class A{}; class B:public A{};  A a;A b = a; 不会有问题,对于指向虚函数的指针采用MemberWise不会存在问题; 但是对于 A a; B b=a;如果采用MemberWise就会出现问题,这样b对象中的虚函数指针就会指向a的虚函数表,显然是错误的;

三、程序转换语意

1、明确的初始化

2、参数的初始化:

  void foo(X xx){};  

  void fun(){X a; foo(a);}

  ==>

   void foo(X &xx){};

   void fun(){X a; X temp; temp.X::X(a); foo(temp)}

3、返回值的初始化:

      X bar(){X xx; return xx;}  ==> void bar(X& _result){X xx; _result.X::X(xx); return;}

  X xx = bar(); ==> X xx; bar(xx);

  bar().Function(); ==>X xx; bar(xx); xx.Function;

4、在使用层面做优化:直接传入引用就可以解决

5、编译器优化:

四、数据成员的初始化队列

1、四种情况必须要用到初始化队列,否则编译通不过

  a、有const member时

  b、有reference member时

  c、有member class object,且object构造函数带参数时

  d、有Base clase,且构造函数带参数时

2、class Worl{string _name; int cnt; public: Worl(){_name = 0; cnt=0;}}构造函数实际上扩充为如下:

  Worl(){_name.String::String(); String temp = 0; _name.String::operate =(temp); temp.String::~String(); cnt=0};

  可以看出对_name初始化调用了两次构造函数,一次析构函数,还有一次赋值操作;

  如果写为Worl():_name(0){ cnt=0;}会扩充为:Worl(){_name.String::String(0); cnt=0};只调用了一次拷贝构造函数,效率大大提升

3、初始化队列并不是通过函数调用实现的,而是编译器通过构造函数的代码扩充来完成的,扩充在用户代码之前,以某一顺序来完成:从后向前or从前向后

4、Worl():cnt(0){} 会扩充为 worl(){cnt = 0};所以对于基本数据类型的话两种写法的效率是一样的

原文链接: https://www.cnblogs.com/liao-xiao-chao/archive/2011/10/11/2207769.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    《深度探索C++对象模型》—— 构造函数篇

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/34007

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午11:04
下一篇 2023年2月8日 上午11:04

相关推荐