从没有虚拟析构函数的类继承

Ben*_*ley 7 c++ inheritance

我一直听说你不应该从没有虚拟析构函数的类中继承,而且我没有太注意,因为我只是不经常使用继承.即使您不想使用多态,此规则也适用,但您只想要所有类功能,并且还想添加更多功能?具体来说,只要我没有多态地使用它,下面的类是否安全,行为定义明确?(即没有删除派生对象的基本指针)

template<typename T>
class SomewhatSafeVector : public std::vector<T>
{
public:
    typedef std::vector<T> base;

    T& operator[](unsigned n) {
        if (n >= base::size())
        {
            throw IndexOutOfBounds();
        }
        return base::operator[](n);
    }
};
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 7

我一直听说你不应该从没有虚拟析构函数的类继承

这是给初学者的一个经验法则,因为解释所有错综复杂需要花费太多时间,并且实际上只给他们几条基线一直工作的更安全(并且对于练习计划来说并不是那么昂贵)(尽管可能是矫枉过正).

您可以virtual在基类中完美地使用继承而不使用析构函数.另一方面,如果基类根本没有virtual方法,那么继承可能是该作业的错误工具.例如:在你的情况下,如果我使用SafeVector<T> sv; sv[3];那么它是安全的,但是如果我这样做std::vector<T>& v = sv; v[3];不是...这是因为你只是隐藏基类方法,而不是覆盖它(提高你的警告级别,他们会让你懂).

这里的正确方法是使用组合,然后为实际成员创建转发方法,以实现您真正使用的方法.在实践中,它很累,因为C++不支持委托(using attribute.insert;)这么多人诉诸继承...

另一种方法是提供更安全的方法作为自由方法,因为您始终可以无限制地添加自由方法.对于具有"OO"思维模式的人来说,它可能会觉得不那么惯用,而且有些运营商不能这么做.


Alo*_*ave 5

如果您不打算以多态方式使用该类(不删除派生对象的基本指针),那么它不是未定义的行为.

参考:

C++ 03标准:5.3.5删除

5.3.5/1:

delete-expression运算符销毁由new-expression创建的派生程度最高的对象(1.8)或数组.
delete-expression
::: opt delete cast-expression
:: opt delete [] cast-expression

5.3.5/3:

在第一个替代(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义.在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为是未定义的.73)