Default Constructor 的构造操作

当编译器需要的时候,而不是程序员需要(初始化为0的操作),一个nontrivial default constructor就是编译器所需要的那种,必要的话由编译器合成出来。
nontrivial default constructor 的4种情况:
1. “带有Default Constructor”的Member Class Object
如果一个class 没有任何constructor,但它内含一个member object,而后者由default constructor,那么这个class的implicit default constructor就是“nontrivial”,编译器需要为该class合成出一个default constructor。不过这个合成操作只有在constructor真正需要被调用时才会发生。

class Foo {
public:
    Foo();
    Foo(int);        
};
class Bar {
private:
    Foo foo; // 初始化foo是编译器的责任
    char*str; // 初始化str为是程序员的责任
};

void foo_bar(){
    Bar bar; // Bar::foo 必须在此处初始化,是一个member object,class Foo 拥有default constructor。
    /*  Bar的default constructor可能会被这样合成
        inline Bar::Bar()
        {
            foo.Foo::Foo();
        }
    */
}

2. “带有Default Constructor”的Base Class
如果一个没有任何constructors的class派生自一个“带有default constructor”的base class,那么这个derived class 的default constructor会被视为nontrivial,并因此需要被合成出来。它将调用上一层base classes的default constructor(根据它们的声明顺序)。如果同时也存在“带有Default Constructor”的Member Class Object,那些default constructor也会被调用–在所有base class constructor都被调用之后。
3. “带有一个Virtual Function”的Class
a. class 声明(或继承)一个virtual function。
b. class 派生自一个继承串链,其中有一个或更多的virtual base classes。
下面两个扩张行动会在编译期间发生:
a. 一个virtual function table(vtbl)会被编译器产生出来,内放class的virtual functions地址。
b.在每一个class object中。一个额外的pointer member(vptr)会被编译器合成出来,内含相关之class vtbl的地址。

class Widget {
public:
    virtual void flip() = 0;
}
void flip(const Widget& widget)
{
    widget.flip();
    // (*widget.vptr[1](&widget))
    // 1 表示flip()在virtual table 中的固定索引
    // &widget代表要交给“被调用的某个flip()函数实例”的this指针
}

编译器必须为每一个类对象的vptr设定初值,放置适当的virtual table地址。对于class所定义的每一个constructor,编译器会安插一些代码做这样的事情。对于那些未声明任何constructors的classes,编译器会为它们合成一个default constructor,以便正确地初始化每一个class object的vptr。
4.“带有一个Virtual Base Class”的Class
Virtual Base Class的实现法在不同的编译器之间有极大的差异。然而,每一种实现法的共同点在于必须使virtual base class 在其每一个derived class object中的位置,能够于执行期准备妥当。

class X {public: int i;};
class A : public virtual X{public:int j;};
class B : public virtual X{public: double d;};
class C : public A, public B {public: int k;};
// 无法在编译时期决定(resolve)出pa->X::i的位置
void foo(const A* pa) {pa->i = 1024;}
// 可能的编译器转变操作 void foo (const A* pa) {pa->_vbcX->i = 1024;} _vbcX表示编译器所产生的指针,指向virtual base class X
main(){
    foo(new A);
    foo(new C);
}

原先cfront的做法是靠“在derived class object的每一个virtual base classes 中安插一个指针”完成。所有“经由reference或pointer来存取一个virtual base class”的操作都可以通过相关指针完成。vbcX(或编译器所做出的某个什么东西)是在class object 构造期间被完成的。对于class定义的每一个constructor,编译器会安插那些“允许每一个virtual base class的执行期存取操作”的代码。如果class没有声明任何constructors,编译器必须为它合成一个default constructor。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值