编译器会自动生成default constructor,这是真的吗?

编译器会自动生成default constructor,这是真的吗?
相信很多人的回答都是“是的吧“。Okay,是不是真的先不提了,先来看一个例子看看下面的代码能否编译通过,如果编译通过,能运行吗?如果不能运行,在哪出错?
class foo {
public:
        int val;
        foo *pNext;
};

void Test1(){
        foo f;
        if (f.val || f.pNext ){
              cout << "in if" << endl;
       }
}

int main(){
       Test1();
        return 0;
}
     事实上,上述代码可以编译通过,但是不能够运行。在if判断那里出错了,因为f没有初始化。这时候有些人就开始有凝问了,f 不是由编译器产生类foo的默认构造函数来初始化吗?好,我们先来看看编译器什么时候编译器产生默认构造函数?
     C++手册中说" 默认构造函数会在 需要的时候被编译器产生出来”关键是需要的时候。上面的例子也是需要啊,咋就没有产生默认构造函数喃?原因是,需要的时候这个有两层意思:一个是程序的需要,另一个是编译器的需要。程序如果需要,那就是程序员的责任,上面的例子就是程序的需要,所以就是设计该类的人负责设计初始化代码。
     那什么时候才会合成出一个默认构造函数?答案是当编译器需要的时候,并且并合成出来的构造函数只执行编译器所需的动作。
     C++ standard中说明“对于class X,如果没有任何user-defined constructor,那么会有一个default constructor被隐式(implicitly)声明出来,一个被隐式声明出来的default constructor将是一个trivial(没啥用的)constructor。
补充:
     上述代码在vs上编译会报错,说使用了未初始化的局部变量。而在gcc编译器上却是可以编译通过并可以运行的。在这方面看来vs还是严格遵守C++标准的。
     对于这一点,在C++ Primer(第四版)第392页关于默认构造函数小节也进行了说明。“ 合成的默认构造函数使用与变量初始化相同的规则来初始化成员。具有类类型的成员通过运行各自的默认构造函数来进行初始化。内置和复合类型的成员,如指针和数组,只对定义在全局作用域中的对象来初始化。当对象定义在局部作用域中时,内置或复合类型的成员不进行初始化。”
     nontrivial default constructor就是编译器需要的默认构造函数。下面主要看4种生成nontrivial default constructor的情况。

一、”带有Default Constructor“的Member Class Object
     如果一个class没有任何constructor,但它内含一个member object,而后者有default constructor,那么这个class的implicit default constructor就是”nontrivial“,编译器需要为该class合成一个default constructor。不过这个合成操作只有在constructor真正需要被调用的时候才会发生。
     举个例子,在下面的程序中,编译器为class B 合成一个default constructor:
class A{ public: A(); A(int x){}..... };
class B : { public : A a; char *str };
void Test(){ B b;}
     被合成的B default constructor内含必要的代码,能够调用class A的default constructor来处理member object B::a.但是它并不产生代码来初始化B::str。将B::a初始化是编译器的责任,将B::str初始化则是程序员的责任。
     上述程序还不能运行,因为B::str没有初始化,所以程序员必须提高默认构造函数初始化str。
     如果一个class X内含有一个或一个以上的member class object,那么class A的每一个constructor必须调用每一个member class的default constructor。并且如果有多个class member objects都要求constructor初始化操作,编译器将按照以”member objects在class中的声明顺序“来调用各个constructors。例如,假设有三个类:
class A{ public: A(); ....};
class B{ public: B(); ...};
class C{ public: C(); ...};
以及一个class D:
class D{
public:    
   A a;
   B b;
   C c;
   ...
private:
   int number;
};
     如果D没有定义default constructor,就会有一个nontrivial constructor被合成出来,依序调用A,B,C的default constructor。然而如果D定义了下面的default constructor:
      D::D:B(360){number=90;}
     编译器就会扩张上述构造函数执行操作为 D::D:B(360){A();B(360);C();number=90;}
     
二、"带有Default Constructor"的Base Class
     如果一个没有任何constructors的class派生自一个”带有default constructor“的base class,那么这个derived class的default constructor会被视为nontrivial,并因此需要被合并出来。它将调用上一层base classes的default constructor。
     如果设计者提供多个constructor,但其中都没有default constructor喃?编译器会扩张现有的每一个constructor,将”用以调用所有必要之default constructors“的程序代码加进去。它不会合成一个新的default constructor,因为其他”由user提供的constructors”存在的缘故。如果同时存在“带有default constructor”的member class object,在所有base class constructor都被调用之后,那些default constructor也都会被调用。

三、”带有一个Virtual Function“的class
     这种情况下,编译器会生成默认构造函数,并且执行下面两个步骤,
     1. 一个virtual function table(vtbl) 会被编译器产生出来,内放class的virtual functions的地址。
     2. 在每一个class object中,一个额外的pointer member会被编译器产生出来,内含相关之class vtbl的地址。

四、“带有一个Virtual Base Class”的class
     Virtual Base Class的实现法在不同的编译器之间有极大的差异。然而,每一种现实法的共同点在于必须使virtual base class在其每一个derived class object中的位置能够在执行器准备妥当。(深入探索C++对象模型)

总结:
     被合成出来的implicit nontrivial default constructors只能满足编译器的需要。它之所以能够完成任务,是借着“调用member object或者base class的default constructor”或是“为每一个object初始化其virtual function机制或virtual base class机制”而完成额。至于没有存在这4种情况而又没有声明任何constructor的classes,其拥有的是implicit trivial default constructors,它们实际上并不会被合成出来。
     在合成的default constructor中,只有base class subobjects和member class objects会被初始化。所有其他的nonstatic data member(如整数、整数指针、整数数组等)都不会被初始化。

C++新手一般有两个常见的误解:
     1. 任何class如果没有定义default constructor,就会被合成出来一个。
     2. 编译器合成出来的default constructor会显示设定“class内每一个data member的默认值”

如果你觉得本篇对你有收获,请帮顶。
另外,我本人开通了微信公众号--分享技术之美,我会不定期的分享一些我学习的东西.
你可以搜索公众号: swalge  或者扫描下方二维码关注我

(转载文章请注明出处: http://blog.csdn.net/swagle/article/details/24453257 )


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值