派生类--> 成员类 --> 基类
因为多态
在c++中,可以使用父类指针指向子类,产生多态行为
代码
#include <iostream>
class TestFather{
public:
~TestFather() {
std::cout << "~TestFather()" << std::endl;
}
};
class TestChild : public TestFather {
public:
~TestChild() {
std::cout << "~TestChild()" << std::endl;
}
};
int main() {
TestFather* p = new TestChild();
delete p;
}
//////////////////////////
执行结果
~TestFather()
原因就是,你直接给编译器一个TestFather指针,delete的时候,编译器一看这不就是TestFather,直接调用TestFather析构函数
换成虚析构呢
代码
#include <iostream>
class TestFather{
public:
virtual ~TestFather() {
std::cout << "~TestFather()" << std::endl;
}
};
class TestChild : public TestFather {
public:
~TestChild() {
std::cout << "~TestChild()" << std::endl;
}
};
int main() {
TestFather* p = new TestChild();
delete p;
}
///////
执行结果
~TestChild()
~TestFather()
正确了,在delete的时候,编译器会先看TestFather的析构函数是不是虚函数,如果是的话才会产生正常的析构顺序行为,派生类-->成员类-->基类
虚析构其实也就是虚函数加上析构函数,本质就是会维护一个虚表和指向虚表的指针,在上面代码中TestFather这里面的虚表就只有~TestFather()这一个函数,使用虚函数代表会增加一个指针的内存开销
当我们不定义虚构函数的时候,编译器会默认生成一个什么都不做的析构函数,但是注意了默认生成的析构函数就是普通函数不是虚函数!!!因为虚函数会带来额外开销,c++追求的是速度
就是纯虚函数加上析构函数,一般我们把函数设置纯虚函数都是不想这个类实例化,抽象出来的顶层父类,并且这个纯虚函数不能实现。但是在纯虚析构这里优点不同
代码
#include <iostream>
class TestFather{
public:
virtual ~TestFather() = 0;
};
TestFather::~TestFather() {
std::cout << "~TestFather()" << std::endl;
}
class TestChild : public TestFather {
public:
~TestChild() {
std::cout << "~TestChild()" << std::endl;
}
};
int main() {
TestFather* p = new TestChild();
delete p;
}
//结果和上面的相同
因为析构函数的调用顺序是派生类 成员类 基类,就算你基类是纯虚函数,编译器还是会产生对他的调用,所以要保证为纯虚析构提供函数体,如果你不做编译器会自动加上。
这里的纯虚实现要在外面实现,不能在类中 = 0之后直接实现,那样直接违反了语法
在上面的代码中我们基类设置为纯虚函数的时候,这个virtual关键字会被一直继承下去
代码
#include <iostream>
class TestFather{
public:
virtual ~TestFather() = 0;
};
TestFather :: ~TestFather() {
std::cout << "~TestFather()" << std::endl;
}
class TestChild : public TestFather {
public:
~TestChild() {
std::cout << "~TestChild()" << std::endl;
}
};
class TestSun : public TestChild {
public:
~TestSun() {
std::cout << "~TestSun()" << std::endl;
}
};
int main() {
TestFather* p = new TestSun();
delete p;
}
结果:
~TestSun()
~TestChild()
~TestFather()
所以当基类是virtual函数,无论子类的相同函数加或者不加这个关键字都是virtual的,但是为了其他人看代码方便,建议手动把从基类继承的虚函数加上virtual
明确你的类会不会被继承,当作基类使用,把类的析构函数都设置为虚函数和不设置为虚函数都是不好的
1.如果你的类会被继承,当作基类,那么一定要把基类析构函数设置为虚函数
2.如果你的类不会被继承,单纯的类,那么不需要把析构函数设置为析构函数,因为会浪费空间,多一个虚表指针
原文:https://www.cnblogs.com/zero-waring/p/12968658.html