[英]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.