文档章节

关于默认构造函数

zray4u
 zray4u
发布于 2016/05/07 14:44
字数 1566
阅读 9
收藏 1
点赞 2
评论 0

通常很多C++程序员存在两种误解:

  • 没有定义默认构造函数的类都会被编译器生成一个默认构造函数。
  • 编译器生成的默认构造函数会明确初始化类中每一个数据成员。

C++标准规定:如果类的设计者并未为类定义任何构造函数,那么会有一个默认 构造函数被暗中生成,而这个暗中生成的默认构造函数通常是不做什么事的(无 用的),trivial下面四种情况除外。

换句话说,有以下四种情况编译器必须为未声明构造函数的类生成一个会做点事 的默认构造函数。(nontrivial constructor)我们会看到这些默认构造函数仅“忠于编译器”,而可能不会按 照程序员的意愿效命。

1.包含有带默认构造函数的对象成员的类(带有default constructor的member class object)

如果一个class没有任何constructor,但他含有一个member object,而后者有defautl constructor,那么这个class的implicit

defautl constructor就是“nontrivial”,编译器需要为此class合成出一个default constructor,不过这个合成操作只有在constructor真正需要被调用时发生。

class Foo {public: Foo(); Foo(int);...};

class Bar {public: Foo foo; char str;};

void foo_bar(){

   Bar bar; //Bar::foo应在此处被初始化

if(str){...}

}

被合成的Bar default ctor内含必要的代码,能够调用class Foo的default ctor来处理member object Bar::foo,但并不处理Bar::str。即被合成的default ctor只是为了满足编译器的需要(编译器需要有个地方来初始化Bar::Foo,因为它有自己的default ctor),而不是程序的需要(初始化Bar::str是程序员的动作)。

如果程序员在ctor只显式初始化了Bar::str,但对编译器而言,它还需要初始化member object foo,由于无参构造函数已经被明确定义出来,编译器没办法合成第二个。那么这时候编译器会怎么做呢?

 

编译器的行动是“如果class A内含一个或以上的member class objects,那么classA的每一个constructor必须调用每一个member classs的defautl constructor,编译器会扩张已存在的constructor。在其中安插一些代码。使得user code在被执行之前,先调用必要的default constructor,)

如果有多个class member object都要求constructor的初始化操作,将如何呢?c++要求以“member objects在class中的声明次序”来调用各个constructor。这一点有编译器完成。

例如

Bar::Bar(){ str=0;      }

会被编译器扩展为

Bar::Bar(){ 

     foo.Foo::Foo(); //附加上的编译器代码

            str=0;//显式的程序员代码

}

2.带有defautl constructor“的base class。

如果一个没有定义任何构造函数的类派生自带有默认构造函数的基类,那么编译器为它定义的默认构造函数,将按照声明顺序为之依次调用其基类的默认构造函 数。若该类没有定义默认构造函数而定义了多个其他构造函数,那么编译器扩充它的所有构造函数——加入必要的基类默认构造函数。另外,编译器会将基类的默认构造函数代码加在对象成员的默认构造函数代码之前。(注:对于基类有默认构造函数的,而在子类中无显式构造函数时,编译器对于基类部分的数据以及数据成员不会视而不见的,而且是先基类后对象成员,对于有多个基数的,按照它们在继承列表中的顺序进行调用;当然即使你定义了其他类型的构造函数,编译器也会在后面帮你完成那些你没有显式完成的工作,它会扩充所有你编写的构造函数,当然只是在你没有显式调用基类的哪个构造函数时)。

3.带有一个virtual function的class

另有2中情况,也需要合成出defautl constructor。

1.     这个类自己声明(或者继承)了Virtual Function。

2.     这个类继承自一个继承串链,其中有一个或多个virtual base class。

不管哪一种情况,由于缺乏有user声明的constructor,编译器会详细记录合成一个defautl constructor的必要信息,以下面的程序片段为例;

class Widget{

  public:

       virtual void flip()=0;

     //...

};

void flip(const Wideget& widget) { widget.fiip();}

//假设Bell和whistle都派生子widget

void foo()

{

  Bell b;

Whistle w;

flip(b);

flip(w);

}

这种情况下,编译时,要做如下工作:

1.编译器需要生成一个virtual function table(vtbl)并填充。

2.在class object中,一个额外的pointer member(就是vptr,指向vtbl)会被编译器合成出来。此外虚拟调用会被替换(w.vf() => w.vprt[1])。

为了支持这种功能,编译器必须为每个w对象设置它的vptr(这是成员变量,此时需要指向合适的vtbl),因此编译器需要在default ctor中安插一些代码来完成这种工作。

4.带有一个virtaul Base class的class

virtual base class的实现法在不同编译器之间有极大的差异,然而,每一种实现法的共同点在于必须使virtaul base classs在其每一个derived class object中的位置,能够于执行期准备妥当,例如下面这段程序代码中:

考虑这样的代码:

classX { public: inti; };

classA : publicvirtualX   { public: in tj; };

classB : publicvirtualX   { public: double d; };

classC : publicA, publicB { public: int k; };

//无法在编译期间解析出 pa->X::i 的位置(给一个pa无法确定i的地址)。

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

main() {

   foo( new A );

   foo( new C );

   // ...

}

由于pa的真正类型不确定,所以某些编译器会记录一个指针例(如 __vbcX)来记录X,然后通过这个指针来定位pa指向的i。上述

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

变成了:

void foo( constA* pa ) { pa-> __vbcX ->i = 1024; }

因此,__vbcX这个指针(执行virtual base class)需要在object构造期间设置好。于是编译器需要一个default ctor来完成这个工作。

© 著作权归作者所有

共有 人打赏支持
zray4u
粉丝 0
博文 208
码字总数 187679
作品 0
西城
C++构造函数的默认参数

和普通函数一样,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。 例9.3的问题也可以使用包含默认参数的构造函数来处理...

初雪之音
2016/01/30
44
0
关于C++中的类

(1)对于const成员函数,从const关键字必须同时出现在声明和定义处,若只出现在一处,就会出现编译时错误。 (2)struct关键字和class关键字的区别就是在于默认访问标号不同。如果类是struc...

最新更新消息
2015/10/14
35
0
JavaScript中的普通函数与构造函数比较

构造函数的定义: 构造函数也可以叫构造对象,配合new表达式一起使用。(注意:这个new关键字是必须,如果不加,就不会当成构造函数调用,而只是一个普通的函数。)。从形式上看,一个函数被作...

zwjjap
2016/04/13
113
0
C++对象的复制——具有指针成员的类的对象的复制

//smartvessel@gmail.com class Table{ Name * p; size_t sz; publish: Table(size_t s = 15){p = new Name[sz=s];} ~Table(){delete[]p ;} ...... } void h() { Table t1; Table t2 = t1; T......

nothingfinal
03/08
0
0
XZ_Swift之Swift面向对象

Swift面向对象 1、关于命名空间 在 Swift 中,默认同一个项目中,所有的类都是共享的,可以直接访问,不需要 import 所有对象的属性 var,也可以直接访问到 在Swift中,所有类都默认有一个命名空间...

understand_XZ的博客
2017/12/22
0
0
关于C++一点小知识

问:类实例和类对象有何不同? 答:基本上就是一回事咯。实例化类的时候,将获得一个实例,它也被称为对象。 问:要访问成员,可使用句点运算符(.),也可以使用指针运算符(->).那哪种方式...

文皓
2014/04/18
0
0
Kotlin 学习笔记(2)类和继承

以下是本人的学习笔记,入有任何不妥之处,随时欢迎拍砖指正。 谢谢 1. 类 Kotlin 中使用关键字 class 声明类 2. 构造函数 在 Kotlin 中类可以有一个主构造函数和一个或多个次构造函数 如果主...

tutu__oo
2017/06/28
0
0
Effective C++: std::invoke_result

std::declval 转换任何类型T到右值引用类型(rvalue-reference),可以让我们通过decltype推断成员函数的返回类型,而不需要通过构造函数(既不需要默认构造函数,也不需要我们定义的函数)。 ...

SHIHUAMarryMe
2016/06/18
46
0
C/C++学习之路(一)

C/C++学习之路(一) 今天我想要写的是关于调用构造函数的问题。 首先,我们先来弄懂关于构造函数的定义。在百度百科上,是这么定义的:构造函数 ,是一种特殊的方法。主要用来在创建对象时初...

大黄有故事
2016/10/08
0
0
Java反射reflect

java.lang.reflect提供类和接口,以获取关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对对象上的基...

iborder
2016/10/21
85
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

实现异步有哪些方法

有哪些方法可以实现异步呢? 方式一:java 线程池 示例: @Test public final void test_ThreadPool() throws InterruptedException { ScheduledThreadPoolExecutor scheduledThre......

黄威
33分钟前
0
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

六库科技
今天
0
0
牛客网刷题

1. 二维数组中的查找(难度:易) 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入...

大不了敲一辈子代码
今天
0
0
linux系统的任务计划、服务管理

linux任务计划cron 在linux下,有时候要在我们不在的时候执行一项命令,或启动一个脚本,可以使用任务计划cron功能。 任务计划要用crontab命令完成 选项: -u 指定某个用户,不加-u表示当前用...

黄昏残影
昨天
0
0
设计模式:单例模式

单例模式的定义是确保某个类在任何情况下都只有一个实例,并且需要提供一个全局的访问点供调用者访问该实例的一种模式。 实现以上模式基于以下必须遵守的两点: 1.构造方法私有化 2.提供一个...

人觉非常君
昨天
0
0
《Linux Perf Master》Edition 0.4 发布

在线阅读:https://riboseyim.gitbook.io/perf 在线阅读:https://www.gitbook.com/book/riboseyim/linux-perf-master/details 百度网盘【pdf、mobi、ePub】:https://pan.baidu.com/s/1C20T......

RiboseYim
昨天
1
0
conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
昨天
1
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
昨天
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
昨天
1
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部