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

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

如果内含一个成员变量a,且该成员变量a含有默认构造函数。同时已经对该类定义了默认构造函数但未对a进行操作,则编译器会在自己定义的默认构造函数的开始部分插入一个a所属类的默认构造函数,不然这个自己定义的默认构造函数将会忽视掉a的nontrival默认构造函数。

2.继承自一个类,且该类中有默认构造函数。派生类中没有定义默认构造函数,则编译器会为派生类提供一个上一层基类的默认构造函数。

3.class中声明了一个虚函数。声明了虚函数代表该class中将出现vptr,并需要为虚函数构造一张虚函数表vtbl,这个操作是必须的,因此使该class的默认构造函数成为nontrivial的,因此需要为了这个vptr和vtbl构建默认构造函数,进行初始化操作。

4.带有虚基类的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;};

void foo(const A* pa) {pa->i=1024};

main()

{

............

}

其中,因为pa的类型可以改变,它可以是A*,也可以是C*,因此,在编译期并不能确定pa指向的对象到底是什么,而只能等到执行期才能固定pa->i的具体位置(因为pa可能不同,而虚基类一般是存在最底部的,因此pa->i相对于类的起始地址的偏移会随着pa的不同而不同)。因此,为了实现在执行期能确定i的位置,需要在类中在引入一个指针或类似索引的东西,这样,在编译期就可以转化为 pa->_vbcX->i=1024;而_vbcX是由编译期所产生的指针。这样无论pa是A*类还是C*类,他们都是经由_vbcX找到的i,只要在A中与C中都引入_vbcX,这样他们在执行期都能通过同样的方式来确定i的位置。

而正因为需要引入_vbcX这种形式的指针,因此使该类的初始化变得nontrivial,因此需要引入一个nontrivial的默认构造函数,使类在创建时期就构建一个_vbcX指针。

C++新手一般有两个常见的误解:

1.任何ckass如果没有定义default constructor,就会被合成一个出来。

实际上,只有上述四种情况中才会生成默认构造函数,因为只有上述四种情况下默认构造函数才是nontrivial的,而诸如类中int a;的初始化,这对编译期来说是trivial的,它的初始化是应该交由程序猿们来实现的。

2.编译期合成出来的default constructor会明确设定"class内每一个data member的默认值"。

实际上,只有nontrivial的成员才需要default constructor对他进行初始化,如类中有默认构造函数的成员变量,vptr.....这种情况。

而trivial的成员的初始化工作不是编译期的职责而是程序设计者的职责。

相反,如果class设计的默认构造函数只对trivial的成员初始化了,编译期则会自己在所定义的默认构造函数中插入对nontrivial的初始化操作(按照声明优先顺序)。

原文地址:https://www.cnblogs.com/lxy-xf/p/11038207.html

时间: 2024-11-09 08:28:50

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

C++系统自动生成默认构造函数的情况

(1) 基类存在默认构造函数 class CBaseClass { public: CBaseClass() { m_i = 0; } private: int m_i; }; class CDriveClass: public CBaseClass { public: void func() { } private: }; (2) 成员变量存在默认构造函数 class CTestClass { public: CTestClass() { m_i = 1; } private: int m_i

编译器生成默认构造函数的情况

在类没有显示声明构造函数的情况下,编译器并不总是为我们自动生成默认构造函数,以下4种情况,编译器才会为我们自动生成默认构造函数: 1.类中有一个类成员含有默认构造函数的,编译器会为该类自动生成默认构造函数,自动插入代码,调用该成员的构造函数: 2.基类中含有默认构造函数,编译器会为该类自动生成默认构造函数,自动插入代码,调用基类的构造函数: 3.类中含有虚函数时,由于编译器要为该类生成虚函数表vtable,并为该类的对象生成指向该vtable的vptr,所以需要为该类合成默认构造函数: 4.虚继

C++空类编译器自动生成的6个成员函数、关于构造函数、拷贝构造函数的解释

对于空类,编译器不会生成任何的成员函数,只会生成1个字节的占位符. 有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:默认构造函数.默认拷贝构造函数.默认析构函数.默认赋值运算符 这四个是我们通常大都知道的.但是除了这四个,还有两个,那就是取址运算符和 取址运算符 const. class Empty { public: Empty(); //缺省构造函数 Empty(const Empty &rhs); //拷贝构造函数 ~Empty();

条款6:如果不想使用编译器自动生成的函数,就应该明确的拒绝。

有些情况自己是不希望生成拷贝构造函数以及拷贝赋值运算符的,这种时候不能只是自己不去编写这些函数,因为这样编译器会自动的去生成这些函数.保险一点的做法是将拷贝构造函数以及拷贝赋值运算符都声明为private的.这样既阻止了编译器生成默认的版本,而且又阻止了别人去调用它. 注意上面的这条“将成员函数声明为private而故意的不去实现它”是一种常用手段,即使是标准程序库中有的部分也是这样做的. class HomeForSale//很明显,销售的两个方子一般内容都是不相同的,所以拷贝构造函数以及 {

Effective C++ 之 Item 6 : 若不想使用编译器自动生成的函数,就该明确拒绝

Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 6. 若不想使用编译器自动生成的函数,就该明确拒绝 (Explicitly disallow the use of compiler-generated functions you do not want) 地产中介商卖的是房子,一个中介软件系统自然而然想必有个 class 用来描述待售房屋: cla

Effetive C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就是了.但这个策略对copy构造函数和copy assignment操作符却不起作用,你如果不声明它们,而某些人尝试调用它,编译器会为你声明它们. 这把你逼到了一个困境.如果你不声明copy构造函数和copy assignment操作符,编译器可能为你产出一份,于是你的clas支持copying.如果

effective c++ 条款06:若不想使用编译器自动生成的函数,就该明确拒绝

记住:为防止编译器暗自提供的功能,可将相应的成员函数声明为privae并且不予实现.也可以使用Uncopyable这样的父类实现. 对于独一无二的对象,希望不支持拷贝构造函数和赋值操作符. class HomeForSale { public: ... private: HomeForSale(const HomeForSale&); //只是声明,阻止编译器自动生成 HomeForSale& operator=(const HomeForSale&); } HomeForSale

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

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

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

//############################################################################ /* * 不让编译器自动生成类函数 * * * * 并不是所有的类都需要编译器自动生成类函数 * * 例: 一个"OpenFile" 类表示一个被打开的文件.构造函数至少需要一个文件名作为参数 * 所有不需要默认构造函数 */ 那么如何让编译不自动生成函数 /* * 对于C++ 11: */ class dog { public: