#include <iostream>
class Base {
public:
virtual void print() {
std::cout << "This is Base::print()" << std::endl;
}
virtual ~Base() {} // 确保析构函数是虚函数,防止内存泄漏
};
class Derived : public Base {
public:
void print() override {
std::cout << "This is Derived::print()" << std::endl;
}
~Derived() {}
};
int main() {
Base* ptr = new Derived();
ptr->print(); // 调用Derived类的print函数,展示多态特性
delete ptr;
ptr = nullptr;
return 0;
}
内存分配和释放过程
- 内存分配:
new Derived()
语句在堆上为Derived
对象分配内存。由于Derived
继承自Base
,Derived
对象的内存布局会包含Base
部分和Derived
自身新增的部分。同时,因为Base
中有虚函数,会在对象内存的起始位置放置一个虚函数表指针(vptr),指向虚函数表(vtable),虚函数表中存放着虚函数的实际地址。
- 内存释放:
delete ptr;
语句释放ptr
指向的堆内存。由于Base
的析构函数是虚函数,当delete ptr
时,首先调用Derived
的析构函数,然后调用Base
的析构函数,正确地释放Derived
对象占用的所有内存。如果ptr
赋值为nullptr
,可以防止野指针的产生。
可能出现的内存泄漏问题及解决方案
- 内存泄漏问题:
- 如果
Base
的析构函数不是虚函数,当delete ptr;
执行时,只会调用Base
的析构函数,而不会调用Derived
的析构函数,Derived
类中动态分配的资源(如果有)就无法释放,从而导致内存泄漏。
- 解决方案:
- 将
Base
的析构函数声明为虚函数,如上述代码中virtual ~Base() {}
,这样在delete
指向派生类对象的基类指针时,会先调用派生类的析构函数,再调用基类的析构函数,确保对象占用的所有内存都被正确释放。同时,在delete
后将指针赋值为nullptr
,防止野指针的产生。