C++ - 对象模型之 构造和析构函数都干了什么

来源:互联网 发布:网站关键词排名优化 编辑:程序博客网 时间:2024/04/28 00:32

C++对象模型目录

C++ - 对象模型之 编译器何时才会自行添加构造函数

C++ - 对象模型之 内存布局

C++ - 对象模型之 成员函数调用

C++ - 对象模型之 构造和析构函数都干了什么

C++ - 对象模型之 类对象在执行时是如何生成的

C++ - 对象模型之 模板、异常、RTTI的实现


C++ - 对象模型之 构造和析构函数都干了什么


我们知道,编译器背着我们做了很多其他的事情,这些事情最为复杂的就是构造函数、拷贝构造函数和析构函数。本部分主要分析,编译器给构造函数、析构函数等都增加了什么功能。


构造和析构函数


无继承

如C++代码:
class Toy{public:Toy(){};virtual ~Toy(){}private:virtual void play(){printf("play the toy\n");}};class Child{public:Child():Age(10),name("小明"){}virtual void who(){printf("I am child\n");}virtual ~Child(){}private:int Age;Toy toy;char* name;};int main(){Child child;}

可能会被转化为如下伪码:
Child::Child(){//设置vptrthis->__vptr_Child = __vtbl_Child;//初始化列表Age = 10;name = "小明";toy::Toy();}Child::~Child(){toy::~Toy();}int main(){Child child;child::Child();child::~Child();}

可见至少要做如下几件事情:

构造函数
1. 如果有虚函数,那么先设定vptr指向应该指向的vtbl;
2. 出现在初始化列表中的初始化操作会在构造函数中执行;
3. 如果member object有Default构造函数,即使没有出现在初始化列表中,也要在构造函数中调用该member的构造函数;

析构函数:
1. 如果member object有析构函数,那么要在析构函数中调用该member的析构函数进行析构;

继承

#include <stdio.h>#include <typeinfo.h>class GrandFather{public:GrandFather(){who();}virtual void who(){printf("I am GrandFather\n");}~GrandFather(){who();}void func(){}};class Father : public GrandFather{public:Father(){who();}~Father(){who();}};class Child : public Father{public:Child(){who();}virtual void who(){printf("I am child\n");}virtual ~Child(){who();}private:int Age;};int main(){Child child;}

伪码:
class GrandFather{public:GrandFather(){//设置vptrthis->__vptr = __vtbl_GrandFather;who();}virtual void who(){printf("I am GrandFather\n");}~GrandFather(){//设置vptrthis->__vptr = __vtbl_GrandFather;who();}};class Father : public GrandFather{public:Father(){GrandFather::GrandFather();//设置vptrthis->__vptr = __vtbl_Father;who();}~Father(){//设置vptrthis->__vptr = __vtbl_Father;who();GrandFather::~GrandFather();}};class Child : public Father{public:Child(){Father::Father();//设置vptrthis->__vptr = __vtbl_Child;who();}virtual void who(){printf("I am child\n");}virtual ~Child(){//设置vptrthis->__vptr = __vtbl_Child;who();Father::~Father();}private:int Age;};int main(){Child child;child::Child();}

结果:
I am GrandFather
I am GrandFather
I am child
I am child
I am GrandFather
I am GrandFather

分析:
1. 构造函数先调用base的构造函数,后设置其他变量,包括vptr;
2. 构造函数调用虚函数,会调用它的vptr设置的虚函数,也就是说vptr的该虚函数。该案例,在对象创建过程中,who()会依次调用GrandFather的who(),然后是Father的,由于Father没有重写who,所以调用的还是GrandFather的,最后到了child,调用的是child的who,也就是在创建过程中,对象的类型依次是GrandFather、Father、Child;
3. 析构函数,会首先设置vptr,最后,才调用base的析构函数。所以,在析构过程中,对象的类型,依次是Child、Father、GrandFather;

赋值操作

还记得复制构造函数的bitwise copy吗?赋值操作也有bitwise copy,只要不满足下面的四种情况,对象赋值时,就采用bitwise copy:

1. 内有member object,并且该member class定义了copy assignment operator;

试想,如果我们还是使用bitwise copy,那么该member的copy assignment operator将不会被调用。

2. base class有copy assignment operator

3. 声明了任何的virtual functions

如果一个无继承的类,有virtual functions,是否也不满足bitwise copy呢?我认为,这个时候应该可以进行bitwise copy

4. 继承一个virtual base class


原创粉丝点击