对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 ...
随机推荐
- codevs 2449 骑士精神 (IDDfs)
/* 限制步数 写迭代加深 注意剪枝:当先步数+不同的个数-1>当前限制的步数 就cut */ #include<cstdio> #include<cstring> #i ...
- Flask挺好
很久没写东西了,寒假比较低效,几乎没写代码.只在慕课网上刷完了linux系列课程,现在用linux熟了很多以及看了大部分<鸟叔-linux服务器架设>那本书,虽然对于写代码并没有什么卵用, ...
- HTTPS 部署简要指南
许多Web开发者都知道SSL,但常见的情况是SSL没有完整地部署或者没有部署在它应该部署的地方.这篇关于何时及如何部署SSL的简要指南,将帮助你避免大多数常见错误. 要点 如果你有任何机密信息,或者你 ...
- C# 连接SQL数据库
感觉很有必要总结一下 一:C# 连接SQL数据库 Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;P ...
- SQL Server 2008 R2 的版本和组件
SQL Server 2008 R2 的版本和组件 SQL Server 2008 R2 其他版本 SQL Server 2008 SQL Server 2005 SQL Server 2012 ...
- pt-query-digest 安装及使用
打个草稿 介绍:pt-query-digest 可用于mysql的慢查询的日志分析,分析统计出每种慢查询的基本信息,如响应时间.最大执行时间.最小执行时间.执行时间的中位数等.(当然不只是这个功能) ...
- 武汉科技大学ACM:1001: 猴子选大王
Problem Description n只猴子要选大王,选举方法如下:所有猴子按 1,2 ……… n 编号并按照顺序围成一圈,从第 k 个猴子起,由1开始报数,报到m时,该猴子就跳出圈外,下一只猴子 ...
- (转)Eclipse快捷键大全,导包快捷键:ctrl+Shift+/
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ 当 ...
- jQuery extend方法介绍
jQuery为开发插件提拱了两个方法,分别是: jQuery.fn.extend(object); jQuery.extend(object); jQuery.extend(object);为扩展jQ ...
- php随机抽奖实例分析
<?php header('Content-type:text/html;charset=utf-8'); /** * 抽奖工具 */ class lottery_tool { protecte ...