nontrivial default constructor(重要的默认构造函数)---四种情况

 

一,“带有Default Constructor”的Member Class Object。如果一个class没有任何的constructor,但它内含一个member object,而后者有default constructor,那么这个class的implicit default constructor就是“nontrivial”,编译器需要为该class合成一个defaul constructor。

class Foo{ public: Foo, Foo(int) ...};
class Bar { public: Foo foo, char *str;}; //译注:不是继承,是内含!

void foo_bar()
{
    Bar bar;   //Bar::foo必须在此处初始化
               //译注:Bar:;foo是一个member object,而其class Foo拥有default constructor.
    if(str) { } ...
}

 

程序员也可以自己定义:

Bar::Bar()
{
    foo.Foo::Foo();    //附加的compiler code(编译器代码)
    str = 0;           //explicit user code(显示代码)
}

 

 

二,“带有Default Constructor”的Base Class。如果一个没有任何constructor的class派生自一个“带有default constructor”的base class,那么这个derived class的default class的default constructor会被视为nontrivial,并因此需要被合成出来。

class A1
{
public:
    A1(){cout<<"A1 construction"<<endl;}
};

class A2
{
public:
    A2(){cout<<"A2 construction"<<endl;}
};

class A3: public A1, public A2//注意,这里为声明的顺序
{
public:
    A3(){ 
        A3::A2();
        A3::A1();
        cout<<"A3 construction"<<endl;
    }
};

int main(int argc, char* argv[])  
{  
     A3 a;
     return 0
}

 

运行该程序,发现结果如下:

A1 construction
A2 construction
A2 construction
A1 construction
A3 construction    

Process returned 0 (0x0)   execution time : 0.187 s
Press any key to continue.

// 前两行为编译器调用的,后两行为显示调用的 基类的构造函数

 

三,“带有一个Virtual Function”的Class。

class Widget
{
public:
    virtual void flip() = 0;
    //  ...
};

void flip( const Widget& widget ) { widget.flip(); }

//假设Bell和Whistle都派生自Widget
void foo()
{
    Bell b;
    Whistle w;
    
    flip(b);
    flip(w);
}

 

下面两个扩张行动会在编译期间发生:

1,一个virual function table(在cfront中被称为vtbl)会被编译器产生出来,内放class的virtual function地址。

2,在每一个class object中,一个额外的pointer member(也就是vptr)会被编译器合成出来,内含相关之class vtbl的地址。

 

四,“带有一个Virtual Base Class”的Class。对于一个没有任何constructor的class,编译器会为它合成一个default constructor,在这个default constructor中会安插那些“允许每一个virtual base class的执行期存取操作”的代码。

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;};

// 无法在编译期决定pa->X::i的实际偏移位置
void foo(const A* pa) {pa->i = 1024;}

main()
{
    foo(new A);
    foo(new B);

}


该程序中,编译器无法固定住foo()之中“经由pa而存取的X::i”的实际偏移位置,因为pa的真正类型可以改变。编译器必须改变“执行存取操作”的那些代码,使X::i可以延迟至执行期才决定下来。

 

 

 

 

 

                 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值