编译器会自动生成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。

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
)

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

时间: 2024-08-05 10:48:50

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

空类编译器会自动生成哪些函数

当空类Empty_one定义一个对象时Empty_one pt;sizeof(pt)仍是为1,但编译器会生成6个成员函数:一个缺省的构造函数.一个拷贝构造函数.一个析构函数.一个赋值运算符.两个取址运算符. class Empty { public: Empty();                            //缺省构造函数 Empty(const Empty &rhs);            //拷贝构造函数 ~Empty();                         

深度探索C++对象模型-----编译器’何时‘自动合成nontrivial default constructor

有4种情况,会造成"编译器必须为 未申明constructor的classes合成default constructor. 1.带有default constructor的member class object 如果一个class没有任何constructor,但是内含一个member object ,而后者有default constructor,那么这个class的implicit default constructor就是 nontrivial,编译器需要为改class合成出一个defau

C++如何拒绝编译器自动生成的函数

每一个class,编译器都会自动生成四个特殊成员函数: destructor(析构函数) default constructor(默认构造函数) copy constructor(copy构造函数) copy assignment operator =(copy assignment操作符) 但是有时候我们不想让我们设计的class有某些默认的构造函数.那么我们就应该明确禁止它. 比如我设计的一个class不想有copy构造函数和copy assignment操作符,那么我可以把这两个函数声明为

C++进阶--编译器自动生成的类函数

//############################################################################ /* 在C++ 03标准下 在没有显式定义的情况加,编译器会自动生成以下4个函数 1. 拷贝构造函数 2. 拷贝赋值运算符 3. 析构函数 4. 默认构造函数(只有当没有声明任何构造函数的时候) */ class dog {}; /* 这个看似空的类,其实等效于下面这个类 */ class dog { public: dog(const d

编译器自动生成默认构造函数的四种情况

在以下四种情况中,如果类中没有定义一个默认构造函数,则编译器会自动生成一个nontrivial的默认构造函数,而不是一个不做事情的trivial默认构造函数:1.内含一个成员变量,而这个成员变量所属的类中含有默认构造函数,则此时需要为此类生成一个implicit default constructor(隐式的默认构造函数),这个implicit default constructor是nontrivial的,因为内含的成员变量需要进行默认构造操作. 如果内含一个成员变量a,且该成员变量a含有默认

【Effective c++】条款6:若不想使用编译器自动生成的函数就应该明确拒绝

地产中介卖的是房子,其使用的中介软件系统应该有个类用来描述卖掉的房子 class HomeFoeSale { ......} 但是任何房子都是独一无二的,不应该存在两个房子拥有同样的属性,因此以下操作不应该正确! HomeForSale h; HomeForSale h1(h); //调用复制构造函数 HomeForSale h2 = h; //调用赋值操作符 阻止这两个操作(复制.赋值)可以不声明它们,but自己不声明,编译器会自动生成,并且访问权限还是public.没办法只好声明出来,但是如

Makeflie自动生成依赖,自动化编译

在netbeans里开发,有一个重要文件makefile,是用来编译所有的文件. 项目的目录结构如下,扁平的目录结构,如何实现自动化编译,写makefile呢? 第一版 基础版: CC = g++ CFLAGS = -O3 -DNDEBUG SOURCE =AdaBoost.cpp aodeselect.cpp sample.cpp vfan.cpp kdbext2.cpp tan_gen.cpp petal: ${SOURCE} $(CC) -o [email protected] ${SOU

Default Constructor的构建操作

在<C++ Annotated Reference Manual(ARM)[ELLIS90]>中的Section 12.1告诉我们:"Default constructors...在需要的时候被编译器产生出来". 其实默认构造函数也是分为两类的:有用的(nontrivial ).无用的(trivial ). 所谓有用的标准也是就默认构造函数会为我们的类做一些初始化操作.那么无用的就不会做任何工作,从而对我们的类也就没有任何意义. 所以,我们通常所说的默认构造函数是指有用的默

深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作

C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的设定“class内每一个data member的默认值” 一.编译器在哪种情况下才会合成默认构造函数: 对于未声明构造函数的类,只有在以下四种情况下编译器才会为它们合成默认构造函数: 类的成员有一个类对象(Member Class Object),且该成员含有默认构造函数(default Const