C++ - 对象模型之 构造和析构函数都干了什么
2014-11-27 17:15
357 查看
转自: http://blog.csdn.net/gykimo/article/details/8629896
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 <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 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;
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
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 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
相关文章推荐
- C++ - 对象模型之 构造和析构函数都干了什么
- 浅出C++对象模型——理解构造函数、析构函数执行顺序
- [深度探索C++对象模型] 默认构造函数和拷贝构造函数的构造操作
- C++对象模型之默认构造函数的构造操作
- C++ 将对象的构造和析构函数声明为Protected的结果
- 浅谈C++对象模型——理解构造函数、析构函数执行顺序
- C++对象模型 ch5 构造 析构 拷贝语义学
- 【C++】深度探索C++对象模型之构造、析构、拷贝语意学
- C++对象模型——构造,解构,拷贝语意学(第五章)
- C++对象模型——继承体系下的对象构造(第五章)
- 深入探索C++对象模型--详解深拷贝与浅拷贝以及拷贝构造的建构
- 深度搜索C++对象模型 - 构造语义学
- 深度搜索C++对象模型2.2 构造函数语义学-Copy Constructor的构造操作
- C++对象模型之默认构造函数的构造操作,拷贝构造函数同
- C++面向对象笔记:构造、析构函数、成员函数
- 深度探索C++对象模型:5.构造、析构、拷贝语意学
- c++对象模型-虚拟析构函数
- C++对象模型 第五章 构造、析构、拷贝语意学
- 《深度探索c++ 对象模型》有感之构造函数和析构函数不能调用虚函数