C++对象模型学习笔记(二)--默认构造函数

news/2024/5/20 2:25:51

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

    例如:

    

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

    在上述代码中,line12,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, 而实际上,它并没有被合成出来。

 

    所以,由此可见,以上的两个误解,都是错的。

本文出自 “一步一趋 只求每一步走..” 博客,请务必保留此出处http://neuloner.blog.51cto.com/1479078/307497


http://www.niftyadmin.cn/n/4487355.html

相关文章

javascript闭包浅析

//闭包var myObjectNew (function () {var value 0;return {increment: function (inc) {value typeof inc number ? inc : 1;},getValue: function () {return value;}}}());var quo function (status) {return {get_status: function () {return status;}}};var myQuoN…

Python之爬虫-- XML与XPath

XML XML(EXtensibleMarkupLanguage) 学习文档&#xff1a; http://www.w3school.com.cn/xml/index.asp案例1概念&#xff1a;父节点&#xff0c;子节点&#xff0c;先辈节点&#xff0c;兄弟节点&#xff0c;后代节点 案例1&#xff1a; <?xml version"1.0"…

浅析手机消息推送设计

摘要: 消息是提醒用户有更新的内容&#xff0c;可能短信、邮件、好友申请和日程安排。消息的作用在于主动提醒用户&#xff0c;不需要主动刷新程序或者网页去检查更新&#xff0c;比如Android的sina微博&#xff0c;必须手动刷新程序才能更新微博或者查看好友申请。这种做法可以…

Python之爬虫-- etree和XPath实战

下面代码是在网站上找到的一个例子&#xff0c;空闲的时候可以自己调试。 # -*- coding:utf-8 -*- """ 爬虫 创业邦 创业公司信息爬取 网页url http://www.cyzone.cn/vcompany/list-0-0-1-0-0/0 爬取页面中的创业公司&#xff0c;融资阶段&#xff0c;创业领…

Brackets Sequence POJ - 1141 (区间dp)

Brackets Sequence POJ - 1141 题意&#xff1a;给一个括号序列&#xff0c;问最少添加多少个括号似的原序列匹配&#xff0c;并输出新序列。 用dp[i][j]表示i到j最少添加几个括号&#xff0c;flag[i][j]表示i和j之间需要添加括号的位置。 1 #include<cstdio>2 #include…

Wincc flexable的数据记录的组态

Wincc flexable的数据记录的组态 1.数据记录就是将PLC采集的数据记录下来如下&#xff0c;注意只有TP270和OP270以上的HMI设备才有数据记录 2.练习展示 3.开始创建数据记录 4.组态数据记录 5.组态变量的记录属性。将数据记录和变量绑定起来 1&#xff09;新建连接和变量 2)组态…

Android getWidth和getMeasuredWidth的正解

http://hi.baidu.com/ljlkings/blog/item/fa2a59803f839a82f603a6b2.html?timeStamp1305190390481 一。也許很多童鞋對getWidth()和getMeasuredWidth()的用法有很多的不解&#xff0c;這兩者之間有什麼樣的不同呢&#xff0c;網上也有各種不同的版本&#xff0c;但大多數都大同…

基础备忘:多态的实现(重载、虚函数、抽象类)

1.函数重载 由静态联编支持的多态性称为编译时的多态性或静态多态性&#xff0c;也就是说&#xff0c;确定同名操作的具体操作对象的过程是在编译过程中完成的。在C中&#xff0c;可以用函数重载和运算符重载来实现编译时的多态性。 2.虚函数 由动态联编支持的多态性称为运行…