在文章开始之前,首先指出对于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, 但是这个合成动作只有在调用需要时才会产生。也就是说,在需要时才会合成。

例如:

[cpp] view plaincopy

 
  1. class Foo{
  2. public Foo();
  3. ......
  4. }
  5. class Bar{
  6. Foo foo;
  7. char *str
  8. }
  9. void foo_bar(){
  10. Bar bar;   //bar必须在此初始化
  11. if(str){}.....
  12. }

在上述代码中,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++默认构造函数的理解的更多相关文章

  1. C++的默认构造函数与构造函数

    今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...

  2. C++ 合成默认构造函数的真相

    对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数. 合成默认构造函数会初始化类中所有的数据成员. 第一个误解来自于我学习 ...

  3. 转 关于C#中派生类调用基类构造函数的理解

    关于C#中派生类调用基类构造函数的理解 .c#class       本文中的默认构造函数是指在没有编写构造函数的情况下系统默认的无参构造函数 1.  当基类中没有自己编写构造函数时,派生类默认的调用 ...

  4. C++中关于重载默认构造函数与默认全部参数的构造函数的使用注意

    # include<iostream>using namespace std;class Time{public:                            //公用成员函数  ...

  5. C++对象模型的那些事儿之三:默认构造函数

    前言 继前两篇总结了C++对象模型及其内存布局后,我们继续来探索一下C++对象的默认构造函数.对于C++的初学者来说,有如下两个误解: 任何class如果没有定义default constructor ...

  6. C++对象模型——默认构造函数的合成

    最近在学习C++对象模型,看的书是侯捷老师的<深度探索C++对象模型>,发现自己以前对构造函数存在很多误解,作此笔记记录. 默认构造函数的误解 1.当程序猿定义了默认构造函数,编译器就会直 ...

  7. 【C++】默认构造函数

    参考文献: 1.黄邦勇帅 2.http://www.cnblogs.com/graphics/archive/2012/10/02/2710340.html 3.http://blog.csdn.ne ...

  8. C++ 没有合适的默认构造函数(无参数构造函数)

    本来今天吧,想写一个proxy class的范例,写着写着出了个问题,见如下代码 ; Array1D* _elemArray = new Array1D[_cap]; 同时我为Array1D这个类写了 ...

  9. C/C++ 关于默认构造函数

    前言: 在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是: A() //默认构造函数 ~A() //默认析构函数 A(const A&) //默认拷贝构造函数 A&a ...

随机推荐

  1. MyEclipse设置默认的文档注释

  2. 商品标签例子——CSS3 transform 属性

    积累很重要.从此开始记录前端生涯的点滴.... <!DOCTYPE html><html lang="en"><head> <meta c ...

  3. git some cookies

    *首先得配置和本地的操作实际上都很简单,忽略了:*git 添加远程仓库 git remote add 仓库名 url:*先pull下来,语法 git pull 远程仓库名 远程分支名[:当地分支名], ...

  4. Redis,MemCached,MongoDB 概述

    调研项目主要有Redis. MemCached. MongoDB,以及Amazon的DynamoDB Redis 是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key- ...

  5. Sql server Compact 小型数据库损坏修复

    之前碰到过小型数据库损坏打不开的问题,一直没有理会,今天生产上客户本地小库产生这样的问题,已经修复         SqlCeEngine engine = new SqlCeEngine(" ...

  6. MySQL 行子查询

    MySQL 行子查询 行子查询是指子查询返回的结果集是一行 N 列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集. 一个行子查询的例子如下: SELECT * FROM table1 WH ...

  7. Struts2 模型驱动及页面回显

    * 要从页面中获取表单元素的值,需要在动作类中声明与页面元素同名的属性.导致动作类中既有javabean又有业务方法.        * 将javabean和业务方法进行分离:        * 将重 ...

  8. linux初识-02常用命令

    文件目录操作命令 ls 现实文件和目录列表 ls -l 列出文件的详细信息 ls -a 列出当前目录所有文件 包括隐藏的文件 mkdir 创建目录 -p 父目录不存在的情况下先生成父目录 cd 切换目 ...

  9. JavaScript中的memorizing技术

    今天看<JavaScript>设计模式第七章--工厂模式的时候接触到memorizing技术,简单的说就是对于某个方法,调用它的实例只在第一次调用它的时候才会进行方法中的计算,之后该实例再 ...

  10. WebSQL实例记录

    <table id="content"> </table> <br> <input type="button" id= ...