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

default constructor 会在需要的时候被编译器产生出来,这个需要怎么理解呢?

我们可以看看下面的代码:

class link{public:int val; link *next;}
void text1(){
    link tmp;
    if(tmp.val||tmp.next){
        //
    }
}

在上面的代码中,我们看到,在text1函数里的判断语句是需要tmp里的val或者next有一个具体的值的(要不然怎么判断呢?)而这个情况就属于程序需要,而满足这个这个需要就应该是程序员的事情。但是在看深度探索c++模型的时候我了解到,不管对于程序需要还是编译器需要,都会构造出一个default constructor,而向上面的那段代码,编译器也会生成一个default constructor,但是基本上没什么用,书上叫它(trivial constructor).

当然,有了trivial constructor,也肯定有nontrivial constructor,那么编译器什么时候会合成一个nontrivial constructor 呢?

1.带有默认构造函数的对象成员

首先我们看以下的代码(下列代码来自书上的例子)

class foo{public:foo(),foo(int)...};
class bar{public:foo a;char *str;};

void foo_bar(){
    bar tmp;//在这一步的时候,foo的默认构造函数会被调用
    if(str){};
}

按找之前的说法,这里编译器会生成一个default constructor (for bar),而按照上面的代码来看,这个constructor 得包含能够调用foo::foo()的代码,但是这里要注意,编译器并不会对str进行初始化。编译器生成的default constructor 可能像下面的一样

//c++伪码
inline bar::bar(){
    a.foo::foo();
}

而我们加上程序员写的构造函数后,它会变成这样

bar::bar(){str=0;}
//c++伪码
 bar::bar(){
    a.foo::foo();
    str=0;
}

可以看到,bar 在生成default constructor 的时候,会先去调用含有default constructor 的member object里的default constructor 函数,然后再去调用用户自定义的constructor。

那么看到这里,我们肯定会有疑问,如果含有多个member object 的话,default constructor 将会如何构造,

这里的话,在书上可以看到,c++语言要求以member object 在class的声明顺序来调用各个constructor,然后再去调用用户自定义的constructor。具体可以看下面的代码

class Dopey{public:Dopey();};
class Sneezy{public:Sneezy(int );Sneezy();...};
class Bashful{public:Bashful();...};

class show_white{
    public:
    Sneezy one;
    Dopey two;
    Bashful three;
    private:
    int count;
};
show_white::show_white():sneezy(2048){
    count=2048;
}

constructor 会被扩张为
//c++伪码
show_white::show_white()::one(2048){
    one.Sneezy::Sneezy(2048);
    two.Dopey::Dopey();
    three.Bashful.Bashful();
    count=2048;
}
这里着重理解一下扩张

2.该类是继承而来,且父类自带有defult constuctor

class A{
    private:
    int val1;
    int val2;
    public:
    A(){
        ///初始化内容
    }  
};

class B:public A{
    
};

在这里,B会执行A的constructor

3.该函数里面有虚函数

class A{
  public:
    void virtual foo(){};
};
在这里,default constructor会构造出vptr(用于指向虚表),和虚表,
所以它是有用的

4.带有一个virtual base class 的class

class X{public:int i;};
class A:public virtual X{public:int j;};
class B:public virtual X{public:int k;};
class C:public A,public B{public:double m;};
在这里,编译器会给派生类生成一个指针,指向virtual base class ,
可以看下面的代码来理解一下这个
void foo(const A* pa){pa->i=1024}//这个是错的,因为无法在编译器里面决定pa->X::i的偏移位置
所以想出的办法是在每一个派生类里面设置指向virtual base class 的指针,
//如下
void foo(const A* pa)(pa->_vbcx->i=1024;)
  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值