一、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};所以对于基本数据类型的话两种写法的效率是一样的