C++填坑系列:tip7 为多态基类声明virtual析构函数

隐藏

问题的产生

1 derived 类的内存顺序大概是:

 [ base member ] [ base vptr ] [ derived class member ] [ derived vptr ]

2 对于多态,实现方法主要是:

BaseClass* pbase = new DerivedClass();

pbase -> DerivedClass.doSomething();

delete pbase;

如果delete调用了baseClass的non-virtual析构函数, 根据析构函数的判断,数据长度应该是sizeof(baseClass),那么heap中的数据现在是:

                           ↓ derived class 部分未被释放掉 ↓
 [ 被delete了的部分 ] [ derived class member ] [ derived vptr ]

因此出现了内存泄漏

所以,要让编译器明白,此处用到了多态,即base class pointer指向了derived class,析构就调用derived class各自的析构函数吧,因此base class 用virtual 析构

virtual函数与多态的关系

对于多态基类有一个特点,就是一定会有virtual函数,不然怎么实现多态? 因此,也可以认为含有virtual成员函数的基类需要使用virtual析构函数。 当然本质而言,是因为多态下基类指针指向了子类的原因。

virtual函数带来的类体积、可移植性的问题

此外需要说明的是virtual函数会带来对象体积的增加,对于C++的C style部分需要注意,因为加上了虚表指针vptr的类无法与C style数据结构对应。因此在于C交互的时候需要注意,否则不再有可移植性。

当心

例如string类其实不含虚析构的,因此千万不要定义一个类继承自string。 需要的时候查看下lib的源代码判断下即可。

其他不带vitual析构的包括STL的vector、list、set、tr1::unordered_map等。

pure virtual析构函数

所谓pure virtual函数是指包含该函数的类不能拥有实体instance,即抽象类

因抽象类总试图作为base class,如果没有其他函数适合作为virtual函数的话, 可以将析构函数作为纯虚函数。此外,该pure virtual dtor需要提供定义。

示例

//参考自 Effective cpp
class AbstractVirtual {
public:
  virtual ~AbstractVirtual() = 0;
};

AbstractVirtual::~AbstractVirtual() { }
//需要提供定义。因为derived class会调用base class的析构函数,不定义将出现linkage error
-----EOF-----

Categories: c++ Tags: c++