Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从没有虚拟析构函数的类继承_C++_Inheritance - Fatal编程技术网

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

C++ 从没有虚拟析构函数的类继承,c++,inheritance,C++,Inheritance,我一直听说不应该从没有虚拟析构函数的类继承,我也没有太多注意,因为我只是不经常使用继承。即使您不想使用多态性,但您只需要一个类的所有功能,并且您想添加更多功能,这个规则是否也适用?具体来说,只要我没有多态性地使用,下面的类是否安全、行为定义良好?(即,不删除指向派生对象的基指针) 模板 类SomewhatSafeVector:public std::vector { 公众: typedef std::向量基; T运算符[](不带符号的n)(&T){ 如果(n>=base::size()) { 抛

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

模板
类SomewhatSafeVector:public std::vector
{
公众:
typedef std::向量基;
T运算符[](不带符号的n)(&T){
如果(n>=base::size())
{
抛出索引自动边界();
}
返回基::运算符[](n);
}
};

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

参考:

C++03标准:5.3.5删除

5.3.5/1:

delete expression操作符销毁最派生的对象(1.8)或由新表达式创建的数组。
删除表达式:
::选择删除强制转换表达式
::opt delete[]强制转换表达式

5.3.5/3:

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


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

旁白:您可以简化
操作符[]
,从而:

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

是的,如果您从不使用多态性(也就是说,从不向上转换引用或指针),就没有办法执行不安全的销毁

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

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

这是给初学者的一条经验法则,因为解释所有复杂的问题需要太多的时间,而且实际上只给他们几个一直有效的基线(尽管可能有些过分)是更安全的(对于练习程序来说也不会太贵)

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

这里的正确方法是使用组合,然后为您真正使用的方法创建转发方法到实现成员。在实践中,它变得乏味,因为C++不支持委派(<代码>使用Actudio.INSERT;),因此许多人都想继承……/P>
另一种选择是提供更安全的方法作为自由方法,因为您总是可以不受限制地添加自由方法。对于有“OO”思维的人来说,它可能感觉不太习惯,而且一些操作符不能如此添加。

如果不以多态方式使用它,您就可以了。不管它是否正确,但您仍然不应该从标准库容器派生。此外,如果您在访问动态容器的边界内遇到问题,您可能更愿意看看您的全局算法思维(想想“0-1-many”和“ranges”),因为越界访问通常是一个逻辑错误。我认为在您的特定示例中,继承并不是一个非常优雅的解决方案,因为继承是为了接口重用,而不是实现重用。显然,您没有重用该接口,因为您的
操作符[]
会抛出一个异常,而
std::vector
不会。如果您想重用代码,只需使用普通共享函数,或者(如本例中所示)将
std::vector
作为
SomewhatSafeVector
@KerrekSB:的成员,为什么不呢?第二,我没有这样的麻烦。但我认为边界检查容器对于教学和调试来说是个好主意。@FrerichRaabe:我大体上同意。我已经用边界检查迭代器完全实现了一个边界检查向量类。我只是想知道我是否可以通过使用继承来节省一些时间,这样就不会重写不需要边界检查的函数。
T& operator[](unsigned n) { return this->at(n); }