/*
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。
这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,
无论什么事都可能发生。(实际运行时经常发生的是,派生类的析构函数永远不会被调用。在本例中,这意味着当targetptr 删除时,
enemytank的数量值不会改变,那么,敌人坦克的数量就是错的,这对需要高度依赖精确信息的部队来说,会造成什么后果?)
为了避免这个问题,只需要使基类的析构函数为virtual。声明析构函数为虚就会带来你所希望的运行良好的行为:对象内存释放时,
基类和派生类的析构函数都会被调用。
实际上,很多人这样总结:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。
这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,
无论什么事都可能发生。(实际运行时经常发生的是,派生类的析构函数永远不会被调用。在本例中,这意味着当targetptr 删除时,
enemytank的数量值不会改变,那么,敌人坦克的数量就是错的,这对需要高度依赖精确信息的部队来说,会造成什么后果?)
为了避免这个问题,只需要使基类的析构函数为virtual。声明析构函数为虚就会带来你所希望的运行良好的行为:对象内存释放时,
基类和派生类的析构函数都会被调用。
实际上,很多人这样总结:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。
*/
#ifndef PERSON_H
#define PERSON_H
#include <iostream>
class Person
{
public:
int ID;
public:
Person();
Person(int id);
virtual ~Person(); /// 如果基类的析构函数不是虚函数,那么用基类指针释放派生类的时候,不会调用派生类的析构函数。
/// 可以把virtual关键字注释然后查看输出和不注释virtual关键字输出的不同。
virtual int get_num(){return num;}
static int num;
};
#endif
class Child : public Person
{
public:
Child(){num++;}
virtual ~Child(){num--;}
virtual int get_num(){return num;}
private:
static int num;
};
class Adult : public Person
{
public:
Adult(){num++;}
virtual ~Adult(){num--;}
virtual int get_num(){return num;}
private:
static int num;
};
#include "vld.h"
#include "vldapi.h"
#include "person.h"
#include <iostream>
using namespace std;
int main()
{
Person* p=new Person();
Child c;
Adult a;
Person* child =new Child();
cout<<child->get_num()<<endl;
Person* adult = new Adult();
cout<<adult->get_num()<<endl;
cout<<p->get_num()<<endl;
delete child;
cout<<c.get_num()<<endl;
}