C++构造函数语意学 - Constructor(The Semantics of Constructors)

1.默认构造函数(Default Constructor)

default constructors 在编译器需要时被合成出来。被合成出来的constructor只执行编译器所需的行动。也就是说default constructor不会将data members(如 int型)初始化,而是处理member object(成员对象)等编译器的需求。

对于class X ,如果没有任何user-declated constructor,那么会有一个default constructor被隐式声明出来,一个被隐式声明出来的default constructor将是一个trivial(没啥用的) constructor

2.由编译器合成constructor或改造user-declated constructor的四种情况

①带有Default Constructor 的 Member Class Object
如果一个class没有任何constructor,但它内含一个member object,而后者有default constructor,那么这个class的implicit default constructor就是nontrivial.
例:

#include <iostream>
class A{
public:
    A(){
        printf("A Constructor\n");
    }
};

class B{
public:
    int i;
    A a;//class A中有Default Constructor
};


int main(int argc, const char * argv[]) {
    B b;//此时B的constructor调用了A的constructor
    printf("%d\n",b.i);//实际输出为0,可能是由于编译器优化。
    return 0;
}
输出:
A Constructor
0

class B被合成的Default Constructor可能是这样:

B::B(){
    a.A::A();
}

假如定义了B的constructor如下

B::B(){
    i = 100;
}

编译器将会改写B的constructor如下

B::B(){
    a.A::A();//将按声明顺序先调用class member objectsconstruct
    i = 100;//再调用用户所写的代码(explicit user code)
}

②带有Default Constructor的Base Class
例:

#include <iostream>
class A{
public:
    A(){
        printf("A Constructor\n");
    }
};

class B: public A{
public:
    int i;
};


int main(int argc, const char * argv[]) {
    B b;//此时B的constructor调用了A的constructor
    return 0;
}
输出:
A Constructor

详情与①类似,如果同时存在有Default Constructor的Base Class和 Member Class Object,将先按顺序的调用Base Class的Default Constructor,再调用Member Class Object的Default Constructor。

③带有virtual Function 的 class

编译器会发生两个扩张行动在编译期间:
1.一个virtual function table(vtbl)会被编译器产生出来,内放class的virtual functions地址
2.在每一个class object中,一个额外的pointer member(就是vptr)会被编译器合成出来,内含相关之class vtbl的地址
此外虚拟调用操作将会被改写

virtualBaseClassObject.virtualFun()

会被改写成:

(*virtualBaseClassObject.vptr[1])(&virtualBaseClassObject)

1表示virtualFun()在virtual table中的固定索引值。
&virtualBaseClassObject表示调用virtualFun()的实例的this指针。

④在Virtual Base Class的Class

#include <iostream>
class X{
public:
    int i;
};

class A:virtual public X{
public:
    int j;
};

class B: virtual public X{
public:
    int k;
};

class C: public A, public B{
public:
    int g;
};
//无法在编译时期决定pa的类型和pa->X::i的位置
void foo(A* const  pa){
    pa->i = 1024;
}
int main(int argc, const char * argv[]) {
    foo(new A);
    foo(new C);
    return 0;
}

编译器将

void foo(A* const  pa){
    pa->i = 1024;
}

转化为

void foo(A* const  pa){
    pa->_vbcX->i = 1024;
}

其中_vbcX表示编译器所产生指向virtual base class X的指针
而_vbcX是在class object构造期间被完成的,编译器会安插这些代码在constructor中。

3.常见的两个误解:

1.任何class如果没有定义default constructor,就会合成一个
2.编译器合成出来的default constructor会显示的设定class内每一个data member的默认值。(某些编译器会优化,为每一个data member赋默认值,然而这不是c++标准所定义的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值