转自: http://blog.csdn.net/gykimo/article/details/8629896
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(){
- //设置vptr
- this->__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(){
- //设置vptr
- this->__vptr = __vtbl_GrandFather;
- who();
- }
- virtual void who(){printf("I am GrandFather\n");}
- ~GrandFather(){
- //设置vptr
- this->__vptr = __vtbl_GrandFather;
- who();
- }
- };
- class Father : public GrandFather
- {
- public:
- Father(){
- GrandFather::GrandFather();
- //设置vptr
- this->__vptr = __vtbl_Father;
- who();
- }
- ~Father(){
- //设置vptr
- this->__vptr = __vtbl_Father;
- who();
- GrandFather::~GrandFather();
- }
- };
- class Child : public Father
- {
- public:
- Child(){
- Father::Father();
- //设置vptr
- this->__vptr = __vtbl_Child;
- who();
- }
- virtual void who(){printf("I am child\n");}
- virtual ~Child(){
- //设置vptr
- this->__vptr = __vtbl_Child;
- who();
- Father::~Father();
- }
- private:
- int Age;
- };
- int main(){
- Child child;
- child::Child();
- }
结果:
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