对C++默认构造函数的理解
在文章开始之前,首先指出对于c++新手的两个常见的误解:
一、任何class如果没有定义default constructor,就会被合成出一个来。
二、编译器合成出来的default constructor会明确设定'“class内每一个data member的默认值”。
首先我们来讨论第一个误解。编译器并不是给任何一个没有user-declared constructor的class合成出default constructor,编译器只会在需要的时候才会给没有user-declared constructor的class合成出default constructor。那到底什么时候才是需要的呢?首先我们先看一下C++ standard中的一句话:“对于class X, 如果没有任何user-declared constructor, 那么会有一个default constructor被暗中(implicitly)声明出来……一个被暗中声明出来的default constructor将是一个trivial(无能的) constructor”。对于这句话,首先解释一下,原话中的暗中声明出来并不代表编译器会给他合成出来,对于trivial constructor,编译器是不会给他们合成出来的,编译器会合成出来的只是那些nontrivial default construtor,而到底哪些才算是nontrivial default constructor呢? 《Insider C++》中给出了四种情况。
1、一个class的成员中含有带有default constructor的member class object
如果一个class中含有成员对象,而且这个对象有default constructor,, 那么编译器就会给这个class合成一个default constructor, 但是这个合成动作只有在调用需要时才会产生。也就是说,在需要时才会合成。
例如:
- class Foo{
- public Foo();
- ......
- }
- class Bar{
- Foo foo;
- char *str
- }
- void foo_bar(){
- Bar bar; //bar必须在此初始化
- if(str){}.....
- }
在上述代码中,bar必须在此初始化,当这时,编译器就会给Bar合成一个default constructor,在default constructor中安插代码调用Foo的default constructor,但是有一点,编译器为Bar合成的default constructor不会对str进行初始化,对str进行初始化,那只是程序员需要做的事情,而对于合成出的default constructor,它只满足编译器的需求,而不会去满足程序的需求。
如果class中内含一个以上的含有default constructor的object,那在为class合成的default constructor中,会按照object的声明次序调用object 的 default constructor。
2、 class继承于带有default constructor的base class
如果一个没有任何constructor的派生类继承自一个带有default constructor的base class, 那么这个派生类的default constructor被认为是nontrivial,而对于nontrivial的default constructor, 编译器会为他合成出来。在合成出的default constructor中调用base class的default constuctor.
如果设计者提供了多个constructor,但未提供default constuctor,那编译器不会合成新的default constructor,而是会扩展所有的现有的constructor,安插进去default constructor所必须的代码。如果此类中仍存在第一种情况,也就是说存在有menber object, 而且object含有default constructor, 那这些default constructor 也会被调用,在base class的default constructor被调用后。
3、 这个class中带有virtual function
无论一个class是声明(或继承)了一个virtual function, 还是派生自一个继承串联,其中有一个或多个virtual base class.不管上述哪种情况,由于缺乏由user声明的constructor, 编译器会详细记录合成一个default constructor的详细信息。
在编译期间,会做以下的扩张工作:
(1) 一个virtual function table会被编译器产生出来,内含virtual functions的地址。
(2) 编译器会合成一个vptr, 插入每一个object中。
而合成出来的default constructor,当然会为每一个object 设定vptr的初值。
4、 带有一个virtual base class的class
对于这种情况,是为了初始化虚基类指针。
以上就是对第一个误解的讨论,对于第二个误解,对于合成出的default constructor,只会做一些必要的事情,比如对base class subobject 和member class object进行初始化,而对于一些其他的nonstatic data member如整数,指针,数组等则不会进行初始化,因为那些东西对于编译器来讲并不是必要的。
总结:
以上给大家讲述了那两个误解。希望能够对大家有所帮助。只有那四种情况,编译器才会为未声明constructor的class合成出default constructor,而且被合成出来的constructor只会满足编译器的需要,而不会去满足程序的需要,而他们之所以能够完成任务(满足编译器的需要),是借着调用"member object或base class的default constructor”或是“为每一个object初始化其virtual function机制(包括vtbl的创建和vptr的正确初始化)或virtual base class机制”。而对于没有存在那四种情况并且又没有user-decleared constructor的class,我们称其拥有的是implict trivial default constructor, 而实际上,它并没有被合成出来。
所以,由此可见,以上的两个误解,都是错的。
对C++默认构造函数的理解的更多相关文章
- C++的默认构造函数与构造函数
今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...
- C++ 合成默认构造函数的真相
对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习 ...
- 转 关于C#中派生类调用基类构造函数的理解
关于C#中派生类调用基类构造函数的理解 .c#class 本文中的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1. 当基类中没有自己编写构造函数时,派生类默认的调用 ...
- C++中关于重载默认构造函数与默认全部参数的构造函数的使用注意
# include<iostream>using namespace std;class Time{public: //公用成员函数 ...
- C++对象模型的那些事儿之三:默认构造函数
前言 继前两篇总结了C++对象模型及其内存布局后,我们继续来探索一下C++对象的默认构造函数.对于C++的初学者来说,有如下两个误解: 任何class如果没有定义default constructor ...
- C++对象模型——默认构造函数的合成
最近在学习C++对象模型,看的书是侯捷老师的<深度探索C++对象模型>,发现自己以前对构造函数存在很多误解,作此笔记记录. 默认构造函数的误解 1.当程序猿定义了默认构造函数,编译器就会直 ...
- 【C++】默认构造函数
参考文献: 1.黄邦勇帅 2.http://www.cnblogs.com/graphics/archive/2012/10/02/2710340.html 3.http://blog.csdn.ne ...
- C++ 没有合适的默认构造函数(无参数构造函数)
本来今天吧,想写一个proxy class的范例,写着写着出了个问题,见如下代码 ; Array1D* _elemArray = new Array1D[_cap]; 同时我为Array1D这个类写了 ...
- C/C++ 关于默认构造函数
前言: 在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是: A() //默认构造函数 ~A() //默认析构函数 A(const A&) //默认拷贝构造函数 A&a ...
随机推荐
- Avast注册以及更新
昨天无聊在网上看Avast,然后下了玩. Avast有三种版本,免费版,网络版,高级版. 下了个高级版,在贴吧和论坛找激活码,发现大部分都没用,最后找了一个许可文件 关于Avast的注册,有在线和离线 ...
- php数组操作函数
array 详解PHP ob_start()函数的功能要点 http://developer.51cto.com/art/200912/166834.htm http://blog.csdn.net/ ...
- Linux下安装Oracle 10g(redhat 4)
--注:本篇文章只装Oracle,并没有建库 一:在虚拟机里装个readhat 4系统 二:配IP 配好之后的IP如下: 三:建用户组,用户 注意:oracle用户应具有相同的uid. groupad ...
- 【转】深入理解Java内存模型(一)——基础
并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信 ...
- sqlserver2012 评估期已过问题处理
由于之前安装sqlserver2012忘记输入序列号,现在出现评估期已过的问题,网上忙活半天,才解决,发现网上叙述都很凌乱,而且只有大意,新手很难操作,所以把我操作的过程分享给大家 1 开始菜单找到s ...
- C++拾遗(十三)友元和嵌套类
友元类 使用友元的场合: 1.两个类既不是is-a关系也不是has-a关系,但是两个类之间又需要有联系,且一个类能访问另一个类的私有成员和保护成员. 2.一个类需要用到另外多个类的私有成员. C++p ...
- [转]SGI STL 红黑树(Red-Black Tree)源代码分析
STL提供了许多好用的数据结构与算法,使我们不必为做许许多多的重复劳动.STL里实现了一个树结构-Red-Black Tree,它也是STL里唯一实现的一个树状数据结构,并且它是map, multim ...
- SQL Server 中的SET XACT_ABORT各种用法及显示结果
源地址:http://www.cnblogs.com/rob0121/articles/2320932.html 点击进入 默认行为:默认为SET XACT_ABORT OFF,没有事务行为. S ...
- javascript DOM对象转jquery对象
首先,假设一种情形:要在HTML文件中为一个select对象添加一个函数,这个函数的名字叫dynamic_change(this),当select的option被改变的时候调用onchange事件来处 ...
- phpcms v9 读取地区联动菜单缓存文件
读取缓存文件的方法是 getcache() 在 phpcms\libs\functions\global.func.php 中可找到. 地区联动菜单的缓存文件是 caches\caches_link ...