您的位置:首页 > 编程语言 > C语言/C++

C++ 为多态基类声明virtual析构函数

2018-03-09 16:22 197 查看
20180306 C++ 为多态基类声明virtual析构函数
记录时间的基类和派生类:

class TimeKeeper{
public:
  TimeKeeper();
  ~TimeKeeper();
  ...
}

class AtomicClock: public TimeKeeper{...};//原子钟
class WaterClock: public TimeKeeper{...};//水钟
class WristWatch: public TimeKeeper{...};//腕表

工厂(factory)函数:返回指针指向一个计时对象,factory函数会"返回一个base class指针,指向新生成的derived class对象":
TimeKeeper* getTimeKeeper();//返回一个指针,指向一个
                            //TimeKeeper派生类的动态分配对象

上述程序的问题在于getTimeKeeper返回的指针指向一个derived class对象。

在C++中,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义--实际执行时通常发生的是对象的derived成分没被销毁。这可能形成资源泄露、败坏之数据结构、在调试器上浪费许多时间。
消除这个问题的做法很简单:给base class一个virtual析构函数。此后删除derived class对象就会如你想的那般。是 的,它会销毁整个对象,包括所有的derived class成分,

class TimeKeeper{
public:
  TimeKeeper();
  virtual ~TimeKeeper();
  ...
};
 
TimeKeeper *ptk = getTimeKeeper();
...
delete ptk;//现在 ,行为正确。

像TimeKeeper这样的base classes除了析构函数之外通常还有其他的virtual函数(在不同的derived class中有不同的实现代码),任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。

若class不含有virtual函数,通常表示它并不意图被用作一个base class。当class不企图被当做base class,令其析构函数为virtual往往是个馊主意。

虚函数表(vtbl)  虚表指针(vptr)

欲实现出虚函数,对象必须携带某些信息,主要用来在运动期决定哪一个虚函数该被调用。这份信息通常是由一个所谓vptr(virtual table pointer)虚表指针指出,虚表指针指向一个由函数指针构成的数组,称为虚函数表 vtbl(virtual table);每一个带有虚函数的类都有一个相应的虚函数表,当对象调用某一个虚函数,实际被调用的函数取决于该对象的虚表指针所指向的那个虚函数表--编译器在其中寻找适当的函数指针。

无端的将所有classes的析构函数声明为virtual,就像从未声明它们为虚函数一样,都是错误的,许多人的心得是:只有当class内含至少一个virtual函数,才能为它声明虚的(virtual)析构函数。

析构函数的运作方式是:最深层派生(most derived)的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用。

纯虚函数:
在C++中我们可以将一些类的共性编写到一个抽象的类中叫他抽象类(ABC abstract base class),这个类中必须包含一个纯虚函数,抽象类中不能定义出对象,但是可以作为其他类的基类。在抽象类中可以对纯虚函数进行定义也可以不定义,但是注意纯虚函数一般是通过抽象类派生出来的派生类的差异性函数原型,及不能在抽象类中实现的函数,那么抽象类的特点为:
1、至少包含一个纯虚函数
2、纯虚函数可以定义也可以不定义,但是一般是派生类之间的差异函数不能实现的函数
3、抽象类不能用于定义对象,但是可以声明抽象类的指针和引用
4、抽象类包含析构函数、构造函数
5、纯虚函数包含虚函数的所有特点,比如向上转换时候基类指针自适应、通过虚函数表(virtual function table)

在虚函数原型中,后面加上 =0即可生成纯虚函数:
virtual test(int a) = 0;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: