C++经验(三)--为多态基类声明virtual析构函数

在设计模式工厂(factory)模式中,我们通常会返回一个指针,指向一个子类。即返回一个base class的指针,指向一个新生成的derived class的对象。

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

class Derived1 : public Base{...}
class Derived2 : public Base{...}
class Derived3 : public Base{...}

像下面的函数,返回一个指针,指向一个新生成的Derived 类的对象。

Base* getBase();

被getBase返回的对象都在堆上,也就是资源和内存有程序员自己控制。而为了避免资源和内存的泄漏,将上面函数返回的对象正确的释放是我们必须要保证的。

Base* ptr = getBase();
...
delete ptr;

上面的例子我们正常的进行了析构吗?我们感觉好像是做对了所有的事情,但我们还是没有办法知道程序怎样运行。

问题就在于,函数getBase()返回的是一个指向derived classbase class指针,所以,我们看到的derived class 的对象是由base class指针删除。好巧不巧的是,base class有一个 non-virtual的析构函数

所以实际执行时,derived class 的部分通常是没有被删除的,也就是说derived class中的成员变量等的内存是没有被销毁的,这也就造成了内存和资源的泄漏。

而解决上面问题的方法也是很简单的,就是给base class声明一个virtual 析构函数。此后在删除对象时,就会对所有的对象都进行删除。包括其派生的部分。

class Base
{
public:
    Base(){}
    virtual ~Base(){}
    ...
};

Base* ptr = getBase();
...
delete ptr;

而像上面这种例子,一般情况下,基类 Base 除了virtual 的析构函数之外,还会有一些其他的virtual函数,这个函数在不同的派生类中有不同的实现。

也就是说,当一个类有倾向于被当作基类的时候,一般类中都会至少有一个virtual函数,我们应该将其析构函数声明为virtual类型。这样做的目的是为了避免将delete动作,交由客户来使用,从而出现一些资源泄漏等不必要的问题。

但是,我们给任何一个类都定义virtual析构函数是正确的吗?

其实并不是这样的,如果一个class中不含有virtual类型的函数,通常表示他并不会意图被当作是base class,而如果一个类如果不被当作base class,将其析构函数声明为virtual类型,也会造成内存和资源的浪费。

class Point
{
    public:
        Point(int x, int y);
        ~Point();
        
    private:
        int m_x{ 0 };
        int m_y{ 0 };
}

考虑上面的类。一个点有两个坐标,如果每个int类型占用32bits,那么Point的对象就只占64bits。

但是如果将他的析构函数声明为virtual类型呢?

我们都知道,如果一个类中含有虚函数,类中会自己维护一个虚函数表,用来存储对象被调用虚函数时实际被调用的函数的指针。

也就是说,如果我们将其析构声明为virtual类型,在对象内部增加虚函数表,至少会增加对象大小的50% - 100%。

所以,将不意图做为base class的类的析构函数声明为virtual是错误的。

只有当class内含有至少一个virtual函数时,才为他声明virtual析构函数。

class MyString : public std::string
{
    ...
}

MyString *mps = new MyString("this is a test example");

std::string *ps;
...
ps = mps;

delete ps;

上面的例子我们可能会遇到,这种情况下也会出现不明确行为,因为std::string类是没有virtual类型的虚构函数的。

  • 带多态性质的base class 应该声明一个virtual析构函数,如果class有至少一个virtual函数,就应该声明virtual析构函数。
  • class的设计目的如果不是做为base class使用,或者不是为了具备多态性,就不该声明virtual析构函数。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值