深度探索C++对象模型-构造函数语义学

深度探索C++对象模型 超高清pdf 深度探索C++对象模型 超高清 立即下载

default constructor构建

  • default constructors在编译器需要的时候产生,区别于程序设计者的需要。以下程序进行说明:
class A(public: int v;);
void test(){
    A a;
    //a.v没有初始化,需要设计者自行设计default constructor,编译器并不会合成
    if(a.v)
    //...
}
  • 编译器会合成default constructor的四种情况:
    -带有default constructor的member class object
    -带有default constructor的base class(派生)
    -带有virtual base class的class
    -带有virtual function的class

  • 带有default constructor的member class object

class B{public:B(); //B constructor};
class D{
public:
    B b;
    int v;
};
void test{
    D d; //d.b是member object, class B含有constructor
    //...
}

编译器会为class D合成包含member b初始化的代码。
如果D本身定义了constructor函数,如下:

inline D::D{ v = 0;}

那么合成的constructor函数如下:

inline D::D{
    b.B::B(); //增加的代码
    v = 0; //user code置于编译器增加代码后面
  • 带有virtual function的class
    c++对象模型通过vptr指针指向包含virtual function的表Vtbl实现虚函数访问。因此产生一个class object时,我们需要额外初始化vptr(内涵class vtbl地址),这部分编译器合成。
    出处:http://www.cnblogs.com/skynet/p/3343726.html
    c++对象模型
  • 带有virtual base class的class
class A{public: int i} ;
class B : virtual public A;
class C : virtual public A;
class D : public B,public C;
foo(const A *p) {pa->i=0;}
void test(){
    foo(nwe B);
    foo(new C);
}

编译器无法固定foo()中A::i的实际偏移位置,因此pa的具体类型在执行前位置。所以class D的内存布局中需要一个特殊指针指向其中A的位置。
这部分编译器的constructor和vptr的道理是一样的,只不过virtual base class A本身比较特殊(共享的),需要一个额外指针。
具体参见:http://blog.csdn.net/bluedog/article/details/4711169

copy constructor构建

  • 三种明显对使用copy constructor的情况
    -明确赋初值
class X; 
X b;
X a = b;   //X a(b);

-明确赋初值作为参数传递给某个函数
-函数返回一个class object

  • Bitwise and memberwise copy
    在没有explicit copy constructor情况下,有时编译器可以通过简单的bitwise copy完成初始化化操作,而无需合成copy constructor。例如;
class Word{
public:
    Word(const char*);
private:
    int cnt;
    char *str;
}
Word a("book");
Word b(a); //bitwise copy

memberwise or bitwise copy:简单地将内建或者派生的data member从一个object拷贝到另一个object,而不会出错。即该class展现出“bitwise copy semantics”特性。

  • 需要合成copy constructor
    即该class不满足bitwise copy semantics”特性。有以下四种情况:
    -带有copy constructor的member class object
    -带有copy constructor的base class member(派生)
    -带有virtual function的class
    -带有virtual base class的class
  • 带有virtual function class
    如果采用bitwise copy,则object b将指向class D的virtual table,显然不对。所以编译器需要合成class D的copy constructor,明确将object的vptr指向class B的virtual table。
class Base{
public:
    virtual int a();
}
class Derive: public Base{
public:
    int a();
}
D d;
Base b = d;   //需要编译器合成copy constructor
D d2 = d;   //可以采用bitwise copy
  • 带有virtual base class的class
    编译器需要为class B合成一个copy constructor,设定object b中virtual base class pointer/offset的初值,有时只是简单确定它没有被消抹。确保正确!
class A{public: int i} ;
class B : virtual public A;
class C : public B;

C c;
C c2 = c; //bitwise copy即可
B b = c;  //将其derived class的某个object作为初值时需要合成

程序转化语义学

  • 参数初始化 (函数参数)
    例如:
void foo(A a);  //函数声明
A a;
foo(a);  //object a作为实参传入实际上是copy constructor过程

其中的一种策略是导入暂时性object,如下。调用一次copy constructor, 函数调用结束,该暂时对象被destructor。另外,foo()函数声明也需要修改如下:
void foo(A &a);

    A __tmp0;
    __tmp0.A::A(a);   //调用copy construction
    //重写foo()函数调用,使用暂时对象,
    foo(__tmp0); //__tmp0在函数中直接使用
  • 返回值的初始化
    具体实现也需要引入额外参数。
A foo(){
    A x0;
    //处理x0
    return x0;
}
//具体实现机制
A __return;
void foo(A &__return){
    x0.A::A(); //default constructor
    //处理X0
    __return.A::A(x0); //copy constructor 
    return;
}
  • 编译器层面优化
    即Named Return Value(NRV)优化,NRV优化的目的是减少一次copy constructor。具体如下:
void foo(A &__return){
    __return.A::A();  //default constructor
    //直接处理__return,没有copy constructor
    return;
}

需要注意的是,NRV优化的本质是去掉copy constructor,去掉而非生成它,因此NRV优化的前提是该类有copy constructor。

  • 成员初始化队列(Member Initialization List)
    写一个constructor时,我们有机会设定class members的值,值得初始化在:1)Member Initialization List 2)constructor 函数体内。
    编译器会一一操作initialization list,然后再执行函数体内explicit user code。
    initialization list 的执行次序是class 中成员的申明次序,而非initialization中排列顺序。
    将成员初始化置于Member Initialization List是一种比较优化的方式。
Word::Word() : _name("hi") {_cnt = 0}
//编译器扩张后的程序
Word::Word(){
    _name.String::String("hi"); //initialization list
    _cnt = 0;  //explicit user code
}

下面代码的初始化将导致无法预知的错误,由于i声明在j前面,因此i较j先初始化,而此时j的值无法预知。

class X{
    int i;
    int j;
public:
    X(int val): j(val), i(j){}
}
深度探索C++ 对象模型 深度探索C++ 对象模型 第二章 对象 第二章第一节 类对象所占用的空间 成员函数不占用类对象的内存空间一个类对象至少占用1个字节的内存空间成员变量是占用对象的内存空间成员函数 每个类只诞生 一个(跟着类走),而不管你用这个类产生了多少个该类的对象; 第二章第二节 对象结构的发 阅读详情

相关推荐

深度探索C++对象模型

c++对象模型语言中直接支持面向对象程序设计的部分对于各种支持的底层实现机制说白了是介绍编译器是如何支持、实现C++的面向对象机制的。如,继承、虚函数、指向class members的指针等等,编译器是如何实现的。本书C++语法基于C++95本书出版自2001年,虽然书中用到的标准早已盖棺定论,cfront编译器也早已过时,当时来看一些无法确定的标准、难以实现的技术、功能也早已实现,但是对C++对象模型的某些实现方式依然沿用至今。这本书依然不过时。

surfaceyan的博客 1816

深度探索C++对象模型第2章 构造函数语义学

1.究竟是不是每个类都有构造函数 按照C++标准规定,每个类都有显式的或者隐式的构造函数和拷贝构造函数,但是编译器会区分这个类中的构造函数和拷贝构造函数是有用或者无用的,如果判定为有用,编译器就会将这个构造函数生成代码,如果没用,就不会生成代码。(简单来说就是C++规定了每个类都有构造和拷贝构造函数,但是编译器不一定为每个类生成构造或拷贝构造函数,下面的内容都是指编译以后是否是否具有构造函数,所以也有可能没有) 如果类中已经自定义了构造函数,但是如果编译器判定为有用的构造函数代码仍然会自动加在自定义的构造

LIJIWEI0611的博客 788

深度探索C++对象模型(一):关于对象

世界上第一款c++编译器cfront由Lippman开发的,而本书的作者正是他。 现用C++对象模型c++中,有两种类数据成员:static 和 nonstatic;三种类函数成员:static、nonstatic、virtual。 函数都放到代码区,而static成员都放到静态区,因此 c++对象的大小由 nonstatic类数据成员、内存填充和virtual指针决定,其中virtual指针来源于: virtual function:用以实现动态多态,支持一个有效率的 "执行期绑定" vi

youaremyalllove的博客 1872

第2章构造函数语义学读书笔记——深度探索c++对象模型

第2章 构造函数语义学 2.1 Default Constructor的构建操作 class Foo{public: int val; Foo *pnext;}; void foo_bar(){ // 程序需要bar's members都被清零 Foo bar; if(bar.val || bar.pnext) // ...do something } 上面例子中,程序语义需要Foo有一个default constructor,可以将它的两个members初始化为0

风源- 1055

深度探索C++对象模型》第二章:构造函数语义学

类型转换运算符函数: operator 类型名() { //由类型名来确定返回值类型 实现转换的语句 ... } while(cin >> val) 原理 cin是一个流对象,而>>运算符返回左边的流对象,也就是说cin >> val返回cin,于是while(cin >> val)就变成了while(cin),问题就变成了一个流对...

weixin_34223655的博客 190

深度探索c++对象模型》学习笔记 - 2 构造函数语义学

 1.         全局对象的内存会被初始化为0,但是Local对象由于在stack中,所以不会被清0,而是随机的垃圾数据。2.         Default constructor 的构建。如果没有用户定义的构造函数,则会有一个默认构造函数被implicitly构建出来,但这个构造函数是trivial constructor(没啥用处的)。如下四种情况下的类,编译器会构建nontr

Hisense的专栏 2092

深度探索C++对象模型》学习笔记 — 构造函数语义学(The Semantics of Constructors)

深度探索C++对象模型》学习笔记 — 构造函数语义学(The Semantics of Constructors)一、不安全的转换1、从类到基本类型的不安全转换2、从基本类型到类的不安全转换二、默认构造函数1、trivial 默认构造函数2、编译器创建non-trivial 默认构造函数的条件1 — 带有默认构造函数的 Member Class Object(1)示例(2)问题1:不同的编译模块在包含相同头文件时为包含的类声明多个构造函数怎么办?(3)问题2:已有显式声明的构造函数如何插入必要的初始化代码

coding-hwz 956

深度探索C++对象模型--构造函数语义学

Default Constructor的操作:在需要的时候

豆子的collection 783

深度探索C++对象模型第二章 构造函数语义学

2.1  Default Constructor 的建构操作default constructors 在需要的时候才会被编译器产生出来。只有当编译器需要default constructor的时候才会合成出一个constructor, 只有下面的四种情况才会有nontrivial default constructor产生,其余的都是trivial default constructor1)

jinfeng_wang的专栏 1326

深度探索C++对象模型》阅读笔记(完整版)

深度探索C++对象模型》完整阅读笔记

2401_82413779的博客 1887

深度探索C++对象模型构造函数语义学 第二章笔记

本章主要介绍类的构造函数有关的语义(semantics)1.默认构造函数

刘洋_heaven的博客 355

深度探索C++对象模型》读书笔记第二章:构造函数语义学

深度探索C++对象模型》读书笔记之 构造函数语义学 编译器背着程序员做了很多事,explicit关键字的导入,是为了制止“单一参数的constructor”被当作一个conversion运算符。这一章中,挖掘了编译器对于“对象构造过程”的干涉,以及对于“程序形式”和“程序效率”的冲击。 一.Defalut Constructor的构造过程 关键:是编译器需要(就会合成默认构造函数)...

yhcuac 932

深度探索C++对象模型系列笔记之第二章:构造函数语义学

一.默认构造函数 通常很多C++程序员存在两种误解: 没有定义默认构造函数的类都会被编译器生成一个默认构造函数。 编译器生成的默认构造函数会明确初始化类中每一个数据成员。     比如我们下面一个例子:   class Foo { public: int val; Foo *pnext; };

菜根 762

C++-----深度探索对象模型-第二章-构造函数语义学(二)

1、在严谨的C++用词中,定义是指占用内存的行为。 2、显示初始化 X x0; void foo() { X x1(x0); X x2=x0; X x3=X(x0); } 如上的定义,每一个都明显以x0初始化其对象。那么必要的程序转换有两个阶段,1)重写每一个定义,其中的初始化操作会被剥除。2)类的拷贝构造调用操作被安插进去。这样上面的代码可能会变成下面这...

一个人的学习和碎碎念 253

深度探索C++对象模型读书笔记(二)构造函数语义学

首先是一些阅读本章所需要的英文术语: 这一章主要讲述构造函数以及拷贝构造函数C++中的实现细节,有助于我们认识C++编译器在涉及对象构造时的底层操作。 构造函数 Default Constructor的建构操作 默认构造函数在需要的时候被编译器产生出来。对于下图所示bar对象,并不会有默认构造函数进行调用,其数据成员依然是未定义状态。 用书上的话来讲就是右上图所示,由于该...

weixin_30273931的博客 139
上一篇: c++虚继承对象的内存布局
下一篇: 深度探索C++对象模型-Data语义学
isunn
博客等级 码龄15年 15粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值