C++ virtual destructor
创始人
2024-02-16 12:57:11

what happen when a derived class constructor is called?

我们先了解derived class在调用constructor的时候,首先先调用的是其父类的构造函数
why?
首先我们的derived class obj中有所有的父类class的成员,在derived clas obj中其父类成员的可访问程度根据父类成员所在位置所定(子类对象可以访问父类的public和protected成员),所以在我们的子类构造的时候要先构造父类class(主要将其父类成员初始化)

没有构造函数编译器会默认分配一个编译器给你,其功能仅仅是初始化成员而已

如下图、

#include class Base{
public:Base(){ std::cout<< "constructor of Base " <<'\n'; }
};class Derived: public Base{
public:Derived(){ std::cout << "constructor of derived " << '\n'; }
};int main(){Derived* d1 = new Derived();return 0; 
}

打印如下

constructor of Base 
constructor of derived

当然我们构造子类的时候也可以选择性的调用父类构造函数

#include class Base{
public:Base(){ std::cout<< "constructor of Base " <<'\n'; }Base(int a) : Base_value(a) {std::cout << "constructor of base and init base_value and base_value is " << Base_value << '\n';}int Base_value;
};class Derived: public Base{
public:Derived(): Base(){ std::cout << "constructor of derived " << '\n'; }Derived(int a): Base(a){std::cout << "call second constructor of Base_Value" << '\n';}
};int main(){Derived* d1 = new Derived(100);// Derived obj;return 0; 
}

Class继承中的析构函数

我们上面讲到了子类中其实是有父类的成员,所以在构造子类的时候先调用父类的构造函数构造父类,有构造那么就有析构函数,析构的顺序正好相反,先析构子类,再析构父类如下

#include class Base{
public:Base(){ std::cout<< "constructor of Base " <<'\n'; }Base(int a) : Base_value(a) {std::cout << "constructor of base and init base_value and base_value is " << Base_value << '\n';}~Base(){std::cout << "destructor of Base" <<'\n';}int Base_value;
};class Derived: public Base{
public:Derived(): Base(){ std::cout << "constructor of derived " << '\n'; }Derived(int a): Base(a){std::cout << "call second constructor of Base_Value" << '\n';}~Derived(){std::cout << "destructor of Derived" << '\n';}
};int main(){Derived* d1 = new Derived(100);// Derived obj;std::cout << "---------------" << '\n';delete d1;return 0; 
}

打印如下

constructor of base and init base_value and base_value is 100
call second constructor of Base_Value
---------------
destructor of Derived
destructor of Base

我们再看下面代码在delete derived class的时候只有base的destructor被执行,而derived class的destructor并没有被执行

#include class Base{
public:virtual void fun() {std::cout << "base fun" << std::endl; }~Base() {std::cout << "base destructor" << std::endl;}
};class Derive: public Base{
public:virtual void fun() { std::cout << "derived fun" << '\n';}~Derive() { std::cout << "Derive destructor" <<'\n'; }
};int main(){Base *b1 = new Base();Base *b2 = new Derive();b1->fun();b2->fun();delete b1;delete b2;}

打印如下

base fun
derived fun
base destructor
base destructor

为什么会这样?我们注意我们new完Derived class后将其赋值给Base class指针,此时我们new完Derived class生成的obj1虽然有derived class自有的成员变量,但是obj1归根结底是Base class的obj,所以不可访问Derived Class的额外成员这叫做object slicing
此时又有一个问题诞生,因为我们将子类的对象指针obj1赋值给父类,那么意味着obj1只能使用父类部分的成员,我们直接实例化父类这样实例化后的对象又比obj1占用的空间小,又简单不是挺好吗?为什么还要将子类对象obj1赋值给父类?这里有一个用处,就是父类中的一些成员是virtual,那么子类对象中父类vptr指向的函数为子类override后的地址,如下图

class X {int     x;string str;public:X() {}virtual ~X() {}virtual void printAll() {}
};class Y : public X {int     y;public:Y() {}~Y() {}void printAll() {}
};

Y memory layout

      |                              |          |------------------------------| <------ Y class object memory layout|          int X::x            |
stack |------------------------------||   |              int string::len ||   |string X::str ----------------||   |            char* string::str |         \|/  |------------------------------|      |-------|--------------------------||           X::_vptr           |------|       |       type_info Y        ||------------------------------|              |--------------------------||          int Y::y            |              |    address of Y::~Y()    ||------------------------------|              |--------------------------||               o              |              | address of Y::printAll() ||               o              |              |--------------------------||               o              |              
------|------------------------------|--------|           X::X()             | |------------------------------|       |   |           X::~X()            |       ||------------------------------|       | |         X::printAll()        |      \|/ |------------------------------|  text segment|           Y::Y()             ||------------------------------||           Y::~Y()            ||------------------------------||         Y::printAll()        ||------------------------------||      string::string()        ||------------------------------||      string::~string()       ||------------------------------||      string::length()        ||------------------------------||               o              ||               o              ||               o              ||                              |

上图中Y继承了X,那么Y对象中应该含有X的vptr,上图中Y的确含有X的vptr,但是X的vptr不再指向X的函数而是指向class Y override后的函数
所以我们在析构函数中加上virtual关键字后子类对象memory layout中对应的父类vptr指针(子类没有定义virtual函数,所以子类memory layout中没有关于子类的vptr指针,如果子类对象obj1赋值给父类,那么obj1就会使用其内存中x的vptr指向的虚函数)指向的析构函数变成了子类override的那一个(父类对象memory layout中vptr还是父类virtual function的地址),相反如果我们的子类中没有对父类的虚函数重载定义,那么子类中的vptr指向的是父类函数的地址,然后编译器执行的时候会先在vptr中找对应的函数地址,因为我们子类没有重新定义父类虚函数,那么vptr中指向的还是父类对应的虚函数,则最后编译器执行的是父类的函数而不是子类的函数.

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...