深度探索C++对象模型(5)

上一篇我们对合成确省的构造函数做了一个了解,这一篇我们继续看看构造函数这个有趣的东西.
Copy Constructor是什么?我们经常看到代码中有一些这样的函数调用方式X(X&) (“X of X ref”). 这个函数用用户自定义类型作为参数,那它的参数的构造便是由Copy Constructor负责的. 可见这个玩意非常重要,实际上Copy Constructor是由编译器自动合成的,不需要你去作任何事情,但编译器都做了些什么呢?我们的问题出来了。
我们有三种情况需要用一个对象的内容作为另一个类对象的初值.也就是需要编译器来为我们自动合成Copy Constructor.一种是我们在编程中肯定回用到的由类生成对象例如以下形式:

class ClassA{......}
ClassA a;
ClassA b=a; //一个Class对象以另一个对象做初值

另外的一种情况是以对象为参数在函数中传递看下面的伪码:

//例如我们有一个CUser类
CUser{
CUser();
......
};
//我们还有一个CDatabase类,它有一个AddNew的方法
CDatabase{
......
public:
AddNew(CUser userone);
......}
//我们用CUser类产生了一个对象实例.userone,并将他作为AddNew函数的参数,以便
//AddNew函数能够完成在数据库中增加一条记录,用来记录一个用户的信息
CDatabase db=new CDatabase();
db.AddNew(CUser userone) //在这里,你不用将你的用户类的成员全部展开.

还有一种当然是用做函数的return,例如你可以在CDatabase类中添加一个函数用来读取一个用户的信息例如这样CUser GetUserOne(int userID),通过一个用户的唯一的编号可以获得一个用户的信息,并返回一个CUser类的对象。

我们来看看Copy Constructor是如何工作的.首先Copy Constructor和Default Constructor一样都是在需要的时候由编译器产生出来,一个类如果没有声明一个Copy Constructor就会存在一个隐含的声明(或定义),它也被分为trivial和nontrivial两种.

我们来看书上的例子:

Class Word
{
public:
Word(const char*);
~Word(){delete [] str;}
private:
int cnt;
Char *str;
}
这个类的声明不需要合成出Default Copy Constructor.但当进行如下应用时:
#include "Word.h"
Word noun("lsmodel");
void foo()
{
Word verb=noun;
}

结果将会出现灾难性的后果.为什么?因为我们的逻辑对象verb和全局对象noun都指向了相同的字符串,在退出函数foo()之前verb会执行析构,则字符串被删除,从此全局对象nonu指向了一堆无意义的东西.你可以声明一个explicit copy constructor来解决这个问题,当然还可以让编译器来自动的给你合成一个Copy construct.

我们将上面的Word类改写成下面的样子:

Class Word
{
public:
Word(const String&);//注意这里和我们开始的X(X&)形式一样
~Word();
//......
private:
int cnt;
String str; // 这个成员是String类的对象,String是我们自定义的类型
};
Class String
{
public:
String(const char*);
String(const String&);//这里声明了一个Copy constructir
~String();
//......
}
这时在执行我们的代码
#include "Word.h"
Word noun("lsmodel");
void foo()
{
Word verb=noun;
}

编译器会为我们的Word类合成一个Copy Constructor,用来调用它的str(member class String object)的Copy Constructor.象下面伪码表示的这样:

inline Word::Word(const Word &wd)
{
str.String::String(wd.str);
cnt=wd.cnt;
}

当这个类中有一个或多个虚函数时,或者这个类是派生于一个继承串链,并且这个串中有一个或多个虚拟的基类时.这个类在进行拷贝时便不会展现逐次拷贝(bitwise copy).并且会通过合成的Copy Constructor来重新明确的设定vptr来指向虚函数表,而不是将右边对象的vprt直接拷贝过来.书上的ZooAnimal例子的图可以很清晰的描述出这点。

如果一个对象以另一个对象做初值,而后者有一个Virtual Base Class Subobject,那会怎样呢?任何一个编译器都会做到在派生类对象中的virtual base class Subobject的位置在执行期就准备妥当,但bitwise copy可能会破坏这一位置,因此也需要由编译器合成出一个copy constructor,来安插一些代码来设定virtual base class pointer/offset,对每一个成员执行必要的memberwise初始化操作,以及执行内存相关的工作。

最后我们来总结一下上面说的内容,确实有些乱.雷神越来越觉得自己的缺乏文字描述能力.

我们这篇学习的内容是:当一个对象以另一个对象作为初始值时,会发生什么事情.

分成了两种情况,一种是我们声明了explicit copy constructor,这个不是这篇文章需要搞明白的(我想大家也都很明白了).我们想知道的是我们没有为class声明explicit copy constructor函数时编译器都干了些什么.编译器会为我们合成一个copy constructor.以便适应任何时候的对象被正确的初始化.并且我们了解了有以下四种情况class不在按位逐一进行拷贝.

1.当你设计的类声明了一个explicit copy constructor函数时.
2.当你设计的类是由一个具有explicit copy constructor的基类派生的时.
3.当你设计的类声明了一个或多个虚函数时.
4.当你设计的类派生自一个继承串链,这个继承串链中有一个或多个virtual base classes时.

好了,就到这里吧,休息,休息一下。

时间: 2024-08-31 15:18:44

深度探索C++对象模型(5)的相关文章

深度探索C++对象模型(7)

关于<深度探索C++对象模型>停顿了半个月,今天继续啃这个骨头,我的学习进入了第四章,函数的语意学.先做个复习C++支持三种成员函数:静态.虚.和非静态.每一种函数的调用方式都不同,当然他们的作用也会有区别,一般来说我们只要掌握根据我们的需要正确的使用这三种类型的成员函数便可以了,至于内部是如何运做的我们可以不知.但是<深度探索C++对象模型>正是让我们对这些不知道的东西进行深度探索的一本书.通过前面的学习,我想我知道了一些以前不知道的东西,但是感觉并没有提高多少,也许是我对此书的

深度探索C++对象模型(4)

雷神跌跌撞撞的读完了<深度探索C++对象模型>的第一章,虽然还是有些疑惑,但是已经感到收获很大.按照朋友的说法,第一章是一个概括的介绍,具体的细节会在以后的章节阐述,如果没有通读本书,第一章还是比较不容易理解的.雷神听过之后信心倍增,也不在有初看此书时的"世界末日"的感觉了(在第2篇雷神感到学了近一年的C++,居然水平如此之差),并且通过自己的努力,还是摸到了些门道,所以让我们继续快乐的出发,踏上深度探索C++对象模型的旅程.记住我们在第一篇的小文<坚持不懈,直到成功

深度探索C++对象模型(3)

介绍 多态是一种威力强大的设计机制,允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer和references来支持多态,这种程序风格就称为"面向对象". 大家好,雷神关于<深度探索C++对象模型>笔记终于又和大家见面了,速度慢的真是可以.好了不浪费时间了,直接进入主题. 这篇笔记主要解决了几个常常被人问到的问题. 1.C++支持多重继承吗? 2.结构和类的区别

深度探索C++对象模型(2)

史列因:我刚看了你写的"深度探索C++对象模型(1)",感觉很不错.不过我有一个建议:你说"谁知第一章便如此的难以消化,已经反复读了3遍,还是有些夹生"是很自然的.第一章是一个总览,如果你能全看懂,后面的就没什么看的必要了.第一章的内容后面都有详细介绍,开始只要有个大概印象就可以了.这本书中很多内容都是前后重复的.我建议你先不管看懂看不懂,只管向后看,之后再从头看几遍,那样效果好得多. 我想史列因说的应该是一种非常好的阅读方式,类似<深度探索C++对象模型&g

《深度探索C++对象模型》读书笔记 最后一记

第6章主要讲述了执行期语意学,主要内容是关于数组的在构建和析构是如何进行的. 第7章主要讲述了有关Template的相关内容. 这两章内容散见于<Effective C++>.<More Effective C++>.<C++Primer><C++Templates中 文版>等书籍,如果感兴趣请阅读对应的书籍. 本读书笔记主要想谈一下对语意的理解. 本人认为C++程序设计可以简单分为三个层次:语法层.语言语意层(就像<深度探索C++对象模型>所讲

《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记

来源:http://dsqiu.iteye.com/blog/1669614 之前一直对C++内部的原理的完全空白,然后找到<Inside The C++ Object Model>这本书看了下, 感觉收获很大,因为书写得比较早,有些知识应该要更新,但是还是值得好好研读,由于该书的内容给人比较散的感觉,所以一直想找个时间整理一下,遂成此文,虽然都是抄书上的,但是却让我有了温故而知新的觉悟,附近里有三个好资料,一并共享了!2012年9月2日凌晨 4:31 谢谢 张雨生的歌声的相伴!   <

c++-深度探索C++对象模型 虚函数表指针问题

问题描述 深度探索C++对象模型 虚函数表指针问题 <深度探索C++对象模型>中文版116页, "某些编译器设计了一种优化技术,只要第二个(或后继)base class声明了一个virtual function,而第一个base class没有,就把多个base classes的顺序调换.这样可以在derived class object中少产生一个vptr" vptr是如何减少的,想不明白,跪求解答 解决方案 没有虚函数的基类就不需要vptr了 解决方案二: 这个涉及虚表

深度探索C++对象模型(1)

第一章:关于对象(Object Lessons) 读完这一章使我想到了一个很久以前看到的一个笑话,编写一个HELLO WORLD的程序,随着水平和职务的不一样,程序代码也随着变化.当初看时完全当作笑话来看,现在看来写此笑话的人水平不一般.如果要使你的代码能够最大限度的适应不同的运行环境,和最大限度的复用,则在设计和编写的过程中需要考虑的问题很多,因此代码已变的不在具有C语言的简洁,高效.而牺牲了这些优势换来的是更好的封装.当然如果你只是要打印Hello World则不必这样做了. 以C++的思维

《深度探索C++对象模型》读书笔记(1)

在C++中,有两种class data members:static和nonstatic,以及三种class member functions: static.nonstatic和virtual.已知下面这个class Point声明: class Point ...{ public: Point(float xval); virtual ~Point(); float x() const; static int PointCount(); protected: virtual ostream&

深度探索C++对象模型--------默认构造函数

一:默认构造函数的构建      默认构造函数总是在被需要的时候构建出来!!关键字"被需要的时候"!! class Foo { public: int val; Foo *next; }; void foo_bar() { Foo bar; if(bar.val || bar.next) //do something } 上述的代码,编写者意图对象bar中的data member val 和 next 为0.但是编译器没有义务为你初始化为.首先对于堆栈中的变量都不一定会被初始化为0,而