显示调用:指的是在代码中明确指定要调用的函数名称和参数,这样调用语句明确地指定了要调用的函数。为了避免重复调用父类的析构函数,子类的析构函数应该显式调用父类的析构函数,并且应该在子类析构函数的代码的末尾调用父类的析构函数,确保资源的正确释放。
Child::~Child() {
// 子类特定清理操作
...
// 显式调用父类析构函数
Parent::~Parent();
}
隐式调用:指的是在代码中通过语言规则或编译器自动插入的机制触发函数的调用,而不需要显式指定函数的名称和参数列表。例如,当对象销毁时,译器会自动插入相应的析构函数的调用。
class Parent {
public:
Parent() { ... }
~Parent() { ... }
};
class Child : public Parent {
public:
Child() { ... }
~Child() { ... } // 隐式调用的父类析构函数会放在此处
};
我们创建了一个指向 Derived对象的 Base1指针,然后使用 delete 运算符释放了该指针指向的对象的内存。
#include <iostream>
class Base1 {
public:
~Base1() {
std::cout << "Base1 的析构函数" << std::endl;
}
};
class Base2 {
public:
~Base2() {
std::cout << "Base2 的析构函数" << std::endl;
}
};
class Derived : public Base1, public Base2 {
public:
~Derived() {
std::cout << "Derived 的析构函数" << std::endl;
}
};
int main() {
Base1* ptr=new Derived() ;
delete ptr;
return 0;
}
当你使用 delete 运算符释放一个类指针时,只有该类的析构函数会被调用,而不会调用派生类的析构函数。这是因为 C++ 中的析构函数不是虚函数。
运行结果:
Base1 的析构函数
要实现多态析构,即在派生类中正确调用析构函数,需要将基类的析构函数声明为虚函数。这样,在通过基类指针删除派生类对象时,将正确调用派生类的析构函数。
#include <iostream>
class Base {
public:
virtual ~Base() {
std::cout << "Base 的析构函数" << std::endl;
}
};
class Derived1 : virtual public Base {
public:
~Derived1() {
std::cout << "Derived1 的析构函数" << std::endl;
}
};
class Derived2 : virtual public Base {
public:
~Derived2() {
std::cout << "Derived2 的析构函数" << std::endl;
}
};
class Derived3 : public Derived1, public Derived2 {
public:
~Derived3() {
std::cout << "Derived3 的析构函数" << std::endl;
}
};
int main() {
Base* ptr = new Derived3();
delete ptr;
return 0;
}
运行结果:
Derived3 的析构函数
Derived2 的析构函数
Derived1 的析构函数
Base 的析构函数
在这讲一下析构函数和虚析构函数区别:
虚析构函数允许通过基类指针删除派生类对象并正确调用派生类析构函数,支持多态行为。
非虚析构函数不支持多态,并且在通过基类指针删除派生类对象时只会调用基类析构函数,可能导致意料之外的结果。
因此,当使用继承和多态时,通常应将析构函数声明为虚函数,以便正确销毁对象并释放相应的资源。