C++关于编译器合成的默认构造函数
有两个常见的误解:
1.任何类如果没有定义默认构造函数,就会被合成出一个来。
2.编译器合成的默认构造函数会显式地设定类内每一个数据成员的默认值。
对于第一个误解,并不是任何类在没有显式定义默认构造函数时都会被编译器合成一个默认构造函数。
在以下4种情况下,编译器才会合成默认构造函数,以满足编译器自己的需求(并不是为了满足程序的需求)。
一、父类有默认构造函数(default constructor)
如果一个没有任何构造函数的类派生自 “一个有默认构造函数的” 父类,那么这个派生类的默认构造函数被认为是 ”有用的(被编译器所需求)“,因此需要被合成出来。它会调用父类的默认构造函数。
如果派生类含有多个构造函数,但其中不含默认构造函数,编译器并不会为他合成新的默认构造函数,而是会扩展每一个构造函数,将所有需要调用的默认构造函数的代码安插进去。
二、类中带有类类型成员
如果类A中带有类类型成员,并且这个类类型是有默认构造函数的,那么类A的默认构造函数被认为是 ”有用的“,需要合成。
//X,Y,Z都带有显式默认构造函数
class X
{
public:
X();
};
class Y
{
public:
Y();
};
class Z
{
public:
Z();
};
class A
{
public:
X x; //三个类类型
Y y;
Z z;
A(int a); //带有一个构造函数
private:
int val;
}; //程序员对A的构造函数的实现(你所看到的)
A::A(int a)
{
val = a;
} //编译器扩展合成后(编译器认为应该这样)
A::A(int a)
{
//按声明顺序安插代码,调用构造
x.X::X();
y.Y::Y();
z.Z::Z(); //显式的用户代码
val = a;
}
三、带有虚函数的类
在编译期间会发生两个扩展行动:
1.编译器会产生一个虚表(存放着类内虚函数的地址)。
2.在每一个类对象中,会有一个额外的虚表指针被编译器合成出来,用来指向相关虚表。
四、带有虚基类的类
虚基类的实现必须满足虚基类在其 ”每一个派生子类的对象中的位置“ 能够于执行期准备妥当。
class A
{
public:
int a;
};
class X :public virtual A
{
public:
int x;
};
class Y :public virtual A
{
public:
int y;
};
class Z :public X, public Y
{
public:
int z;
}; //编译时无法确定p->A::a的位置
void fun(X *p){ p->a = ; } //编译时无法确定p的真正类型(基类指针可以指向派生类对象,此时真正类型为派生类类型) int main()
{
fun(new X); //真正类型为X
fun(new Z); //真正类型为Z
return ;
}
编译器无法确定fun()中 ”经由p存取的A::a “的实际偏移位置,因为p的真正类型是可变的,如在main()中既可以是X类型,也可以是Z类型。编译器必须改变存取操作的代码,使A::a延迟到执行时才确定下来。
fun()可以被编译器改写成如下:
//编译器转变操作,其中vcbA是编译器产生的指针,指向虚基类A
void fun(X *p){ p->vcbA->a = ; } //vcbA是在类对象构造期间被完成的
除此四种情况之外,如果类没有声明任何构造函数,他们就会有一个隐式而”无用“的默认构造函数,他们实际上并不会被合成构造出来。
对于第二个误解,在合成的默认构造函数中,只有基类子对象和类类型对象会被初始化,而其他所有的非静态成员(如整数,指针,数组等),都不会初始化,对他们进行初始化的应该是程序员,而非编译器。
注意:值类型的默认值并不是默认构造的初始化。
C++关于编译器合成的默认构造函数的更多相关文章
- 合成的默认构造函数定义为delete的一种情况(针对C++11标准)
1. 默认初始化 如果定义变量时没有指定初值,则变量会被默认初始化,此时变量被赋予了"默认值". 对于类类型的变量来说,初始化都是依靠构造函数来完成的.因此,即使定义某个类的变量( ...
- c++ 2.1 编译器何时创建默认构造函数
我们通常会说当生命一个 class 时,如果我们不为该 class 指定一个 constructor,那么编译器会替我们实现一个 connstructor,那么这种说法一定对吗? 事实上,这是不对的. ...
- C++ 合成默认构造函数的真相
对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习 ...
- C++编译器合成Default Constructor的4种情况
笔记C++编译器为编译器需要合成Default Constructor的4种情况. 1,Class A内含Class B对象,Class A没有Default Constructor时会在编译时合成D ...
- C++对象模型——默认构造函数的合成
最近在学习C++对象模型,看的书是侯捷老师的<深度探索C++对象模型>,发现自己以前对构造函数存在很多误解,作此笔记记录. 默认构造函数的误解 1.当程序猿定义了默认构造函数,编译器就会直 ...
- C++中默认构造函数中数据成员的初始化
构造函数的任务是初始化数据成员的,在类中,如果没有显示定义任何构造函数,编译器将为我们创建一个构造函数,称为合成的默认构造函数,合成的默认构造函数使用与变量初始化相同的规则来初始化成员.即当类中的数据 ...
- 【C++对象模型】构造函数语意学之一 默认构造函数
默认构造函数,如果程序员没有为类定义构造函数,那么编译器会在[需要的时候]为类合成一个构造函数,而[需要的时候]分为程序员需要的时候和编译器需要的时候,程序员需要的时候应该由程序员来做工作,编译器需要 ...
- C++对象模型的那些事儿之三:默认构造函数
前言 继前两篇总结了C++对象模型及其内存布局后,我们继续来探索一下C++对象的默认构造函数.对于C++的初学者来说,有如下两个误解: 任何class如果没有定义default constructor ...
- [C++11] 默认构造函数
类通过一个特殊的构造函数来控制默认初始化过程.这个函数就是默认构造函数.默认构造函数无需不论什么实參. 我们能够显示的定义默认构造函数也能够让编译器为我们生成默认构造函数. 默认构造函数以例如以下规则 ...
随机推荐
- vim/Gvim配置
" Sections:" -> General" -> VIM user interface" -> Colors and Fonts&quo ...
- 点分治练习:不虚就是要AK
[题面] 不虚就是要AK(czyak.c/.cpp/.pas) 2s 128M czy很火.因为又有人说他虚了.为了证明他不虚,他决定要在这次比赛AK. 现在他正在和别人玩一个游戏:在一棵树上随机取两 ...
- UVA 4728 Squares(凸包+旋转卡壳)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17267 [思路] 凸包+旋转卡壳 求出凸包,用旋转卡壳算出凸包的直 ...
- iOS按钮长按
UILongPressGestureRecognizer *longPressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:sel ...
- Java设计模式之装饰模式趣谈
本文由码农网 – 鲁阿皓原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 前情提要:http://blog.csdn.net/baidu_30889437/article/details/ ...
- myEclipse和eclipse修改或复制项目名称后-更新部署名称
一.myEclipse 复制后修改名称,访问不到项目 这是因为,你只是改了项目的名称,而没有改 下面是解决方法: 方法 1.右击你的项目,选择“properties”,在“type filter te ...
- 右下角显示提示窗口(New-Object,COM)
$title=“title”$message="hello,world"有时候,要使用的实例的类保存在独立的库文件中,PowerShell默认未加载,就需要先加载库文件,然后再创建 ...
- css3 -> 多栏布局
在进行多栏布局时.使用bootstrap的栅格系统能够非常轻松的实现效果,事实上css3本身也提供了多兰布局的功能. 比方,我们在一个section标签内填充了非常多内容.同一时候希望内容可以显示成三 ...
- 关于Struts框架简介
一,什么是框架? 所谓框架就是提供了一组统一的接口和编程方式的可以重用组件,同时我们可以在框架中扩充我们自己的特定逻辑. 二,MVC设计模式 将应用程序分为3个部分:模型 Model,视图View,控 ...
- cocos2d-x学习日志(13) --A星寻路算法demo
你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢?如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! A星算法简介: A*搜寻算法俗称A星 ...