为什么把c++类的析构函数声明为虚函数?

来源:互联网 发布:金属探测器软件 编辑:程序博客网 时间:2024/06/01 21:25

  如题,当一个类为基类的时候,通常其析构函数被声明为虚函数,这是为啥?

class BaseCls{public:    BaseCls()    {        printf("BaseCls()\n");    }    ~BaseCls()    {        printf("~BaseCls()\n");    }    void test_func()    {        printf("Base::test_func()\n");    }};class SubCls : public BaseCls{public:    SubCls()    {        printf("SubCls()\n");    }    ~SubCls()    {        printf("~SubCls()\n");    }    void test_func()    {        printf("SubCls::test_func()\n");    }};int main(void){    BaseCls *base = new SubCls;;    base->test_func();    delete base;    return 0;}

  编译运行:
这里写图片描述

  在main()函数中,定义了BaseCls类型指针,根据赋值兼容性原则,该指针可以指向动态生成子类SubCls对象的地址,此时动态生成的SubCls对象已经被充当基类使用,因为BaseCls中的test_func()函数是普通函数(并非虚函数)不能发生多态,所以打印的是基类的”Base::test_func()\n”。

  ”delete base;”代码我们希望用来释放SubCls的空间,即调用SubCls的析构函数,释放完毕后BaseCls的析构函数。然而编译器只是根据指针类型是BaseCls而只是调用BaseCls的析构函数,SubCls的析构函数得不到调用,若在SubCls构造函数中动态分配的空间,在析构函数释放空间,那么这样就造成内存泄漏了。

  如何改进?让基类BaseCls的析构函数声明为虚函数,使其在delete base时发生多态即可:

class BaseCls{public:    //...    virtual ~BaseCls()    {        printf("~BaseCls()\n");    }    //...};

  编译运行:
这里写图片描述

  将构造函数中声明为virtual后,编译器就不会简单的只根据base指针的类型而决定调用对象的构造函数,而是依据指针base所指向的实际对象而调用其构造函数,这不就是多态吗?

  最后,再补充两个问题?
  (1) 析构函数可以被声明为虚函数,那构造函数可以声明为虚函数吗?
  答案是不可以。因为虚函数的调用依靠于虚函数表。然而在构造函数执行完毕后,虚函数表指针才被正确初始化。
  (2) 构造函数可以被声明为虚函数,那么构造函数的实现体中,可以实现多态吗?
  答案还是不可以。因为析构函数一旦别调用,稀虚函数表指针就会销毁了。那么同理,在构造函数中实现体中也不可能发生多态行为,因为在构造函数执行时,虚函数表指针还没被正确初始化。

阅读全文
0 0
原创粉丝点击