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

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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值