default constructor构建
- default constructors在编译器需要的时候产生,区别于程序设计者的需要。以下程序进行说明:
class A(public: int v;);
void test(){
A a;
//a.v没有初始化,需要设计者自行设计default constructor,编译器并不会合成
if(a.v)
//...
}
编译器会合成default constructor的四种情况:
-带有default constructor的member class object
-带有default constructor的base class(派生)
-带有virtual base class的class
-带有virtual function的class带有default constructor的member class object
class B{public:B(); //B constructor};
class D{
public:
B b;
int v;
};
void test{
D d; //d.b是member object, class B含有constructor
//...
}
编译器会为class D合成包含member b初始化的代码。
如果D本身定义了constructor函数,如下:
inline D::D{ v = 0;}
那么合成的constructor函数如下:
inline D::D{
b.B::B(); //增加的代码
v = 0; //user code置于编译器增加代码后面
- 带有virtual function的class
c++对象模型通过vptr指针指向包含virtual function的表Vtbl实现虚函数访问。因此产生一个class object时,我们需要额外初始化vptr(内涵class vtbl地址),这部分编译器合成。
出处:http://www.cnblogs.com/skynet/p/3343726.html
- 带有virtual base class的class
class A{public: int i} ;
class B : virtual public A;
class C : virtual public A;
class D : public B,public C;
foo(const A *p) {pa->i=0;}
void test(){
foo(nwe B);
foo(new C);
}
编译器无法固定foo()中A::i的实际偏移位置,因此pa的具体类型在执行前位置。所以class D的内存布局中需要一个特殊指针指向其中A的位置。
这部分编译器的constructor和vptr的道理是一样的,只不过virtual base class A本身比较特殊(共享的),需要一个额外指针。
具体参见:http://blog.csdn.net/bluedog/article/details/4711169
copy constructor构建
- 三种明显对使用copy constructor的情况
-明确赋初值
class X;
X b;
X a = b; //X a(b);
-明确赋初值作为参数传递给某个函数
-函数返回一个class object
- Bitwise and memberwise copy
在没有explicit copy constructor情况下,有时编译器可以通过简单的bitwise copy完成初始化化操作,而无需合成copy constructor。例如;
class Word{
public:
Word(const char*);
private:
int cnt;
char *str;
}
Word a("book");
Word b(a); //bitwise copy
memberwise or bitwise copy:简单地将内建或者派生的data member从一个object拷贝到另一个object,而不会出错。即该class展现出“bitwise copy semantics”特性。
- 需要合成copy constructor
即该class不满足bitwise copy semantics”特性。有以下四种情况:
-带有copy constructor的member class object
-带有copy constructor的base class member(派生)
-带有virtual function的class
-带有virtual base class的class - 带有virtual function class
如果采用bitwise copy,则object b将指向class D的virtual table,显然不对。所以编译器需要合成class D的copy constructor,明确将object的vptr指向class B的virtual table。
class Base{
public:
virtual int a();
}
class Derive: public Base{
public:
int a();
}
D d;
Base b = d; //需要编译器合成copy constructor
D d2 = d; //可以采用bitwise copy
- 带有virtual base class的class
编译器需要为class B合成一个copy constructor,设定object b中virtual base class pointer/offset的初值,有时只是简单确定它没有被消抹。确保正确!
class A{public: int i} ;
class B : virtual public A;
class C : public B;
C c;
C c2 = c; //bitwise copy即可
B b = c; //将其derived class的某个object作为初值时需要合成
程序转化语义学
- 参数初始化 (函数参数)
例如:
void foo(A a); //函数声明
A a;
foo(a); //object a作为实参传入实际上是copy constructor过程
其中的一种策略是导入暂时性object,如下。调用一次copy constructor, 函数调用结束,该暂时对象被destructor。另外,foo()函数声明也需要修改如下:
void foo(A &a);
A __tmp0;
__tmp0.A::A(a); //调用copy construction
//重写foo()函数调用,使用暂时对象,
foo(__tmp0); //__tmp0在函数中直接使用
- 返回值的初始化
具体实现也需要引入额外参数。
A foo(){
A x0;
//处理x0
return x0;
}
//具体实现机制
A __return;
void foo(A &__return){
x0.A::A(); //default constructor
//处理X0
__return.A::A(x0); //copy constructor
return;
}
- 编译器层面优化
即Named Return Value(NRV)优化,NRV优化的目的是减少一次copy constructor。具体如下:
void foo(A &__return){
__return.A::A(); //default constructor
//直接处理__return,没有copy constructor
return;
}
需要注意的是,NRV优化的本质是去掉copy constructor,去掉而非生成它,因此NRV优化的前提是该类有copy constructor。
- 成员初始化队列(Member Initialization List)
写一个constructor时,我们有机会设定class members的值,值得初始化在:1)Member Initialization List 2)constructor 函数体内。
编译器会一一操作initialization list,然后再执行函数体内explicit user code。
initialization list 的执行次序是class 中成员的申明次序,而非initialization中排列顺序。
将成员初始化置于Member Initialization List是一种比较优化的方式。
Word::Word() : _name("hi") {_cnt = 0}
//编译器扩张后的程序
Word::Word(){
_name.String::String("hi"); //initialization list
_cnt = 0; //explicit user code
}
下面代码的初始化将导致无法预知的错误,由于i声明在j前面,因此i较j先初始化,而此时j的值无法预知。
class X{
int i;
int j;
public:
X(int val): j(val), i(j){}
}