繁体   English   中英

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

[英]Inheriting from classes without virtual destructors

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

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);
    }
};

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

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

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

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

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

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

参考:

C ++ 03标准:5.3.5删除

5.3.5 / 1:

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

5.3.5 / 3:

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

欢迎您以多态方式使用该对象,您无法以多态方式delete它。 如果你避免通过std::vector<>*删除指向你的类对象的指针,那么你是安全的。

旁白 :您可以简化您的operator[]

T& operator[](unsigned n) { return this->at(n); }

是的,如果你从不使用多态(即,从不向上转换引用或指针),则无法执行不安全的破坏。

Mixin类通常以这种方式使用,而CRTP很少暗示虚拟析构函数,以命名几个模式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM