Pyp*_*ros 2 c++ stl vector virtual-destructor
我的一个C++类派生自std::vector它,它可以充当一个容器,也可以对其内容执行自定义操作.不幸的是,编译器抱怨析构函数不是虚拟的,我无法改变,因为它在标准库中.
我做错了什么(你不应该从STL派生)或者我能做些什么来保持编译器的快乐?(appart从停止使用-Weffc ++ :)
编辑:派生类不接触矢量操作算法,而只是为图像矢量添加一些信息,如"元素宽度/高度".举个例子,你可以想到
class PhotoAlbum: public std::vector<Photo> {
String title;
Date from_time, to_time;
// accessors for title and dates
void renderCover(Drawable &surface);
};
Run Code Online (Sandbox Code Playgroud)
您认为相册主要是带有一些元数据(标题和时间)和专辑特定功能的图片集合,例如将某些照片的缩略图渲染到曲面上以制作专辑封面.所以imho,相册IS-A的集合Photo,比它更多的HAS-A这样的收藏.
我没有看到在获得额外"收集"字段的getPhotoVector()方法中获得任何好处PhotoAlbum.
Ste*_*sop 10
拥有一个非虚拟析构函数的公共基类是安全的,但是如果有人为你的类分配一个实例,用new它引用它vector<...>*,然后使用该指针删除它而不将其强制转换为指针,则行为是未定义的到你的班级.因此,您班级的用户必须知道不要这样做.阻止它们的最可靠方法是不给它们机会,因此编译器警告.
要处理这个问题而不必对用户施加这样的奇怪条件,最好的建议是对于C++中的公共基类,析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的(http:// www. gotw.ca/publications/mill18.htm,准则#4).由于析构函数std::vector不是,这意味着它不应该用作公共基类.
如果你想要的只是在向量上定义一些额外的操作,那么这就是C++中的自由函数..无论如何,成员调用语法有什么好处?大多数<algorithm>包括对矢量和其他容器的附加操作.
例如,如果你想创建一个"带有最大大小限制的向量",这将提供vector带有修改语义的整个接口,那么与继承和虚拟调用是常态的语言相比,实际上C++确实使这有点不方便.最简单的方法是使用私有继承,然后对于vector您不想更改的成员函数,将它们带入您的类using:
#include <vector>
#include <iostream>
#include <stdexcept>
class myvec : private std::vector<int> {
size_t max_size;
public:
myvec(size_t m) : max_size(m) {}
// ... other constructors
void push_back(int i) {
check(size()+1);
std::vector<int>::push_back(i);
}
// ... other modified functions
using std::vector<int>::operator[];
// ... other unmodified functions
private:
void check(size_t newsize) {
if (newsize > max_size) throw std::runtime_error("limit exceeded");
}
};
int main() {
myvec m(1);
m.push_back(3);
std::cout << m[0] << "\n";
m.push_back(3); // throws an exception
}
Run Code Online (Sandbox Code Playgroud)
不过,你仍然需要小心.C++标准不保证vector相互调用哪些函数,或以何种方式调用.在那些调用确实发生的地方,我的vector基类无法调用重载myvec,所以我改变的函数根本不适用 - 这对你来说是非虚函数.我不能只超载resize()的myvec,并用它做,我必须每天超负荷改变大小的功能,使他们所有的呼叫check(直接或通过调用对方).
你可以从标准中的限制中推断出有些事情是不可能的:例如,operator[]不能改变向量的大小,所以在我的例子中我可以安全地使用基类实现,而我只需要重载函数这可能会改变大小.但是,该标准不一定能为所有可想到的派生类提供这种保证.
简而言之,std::vector不是设计为基类,因此它可能不是一个表现良好的基类.
当然,如果使用私有继承,则无法传递myvec给需要向量的函数.但那是因为它不是一个向量 - 它的push_back函数甚至没有与向量相同的语义,所以我们使用LSP进行狡猾的讨论,但更重要的是对vector忽略我们的重载的函数进行非虚拟调用.如果按照标准库预期的方式执行操作,那就没关系 - 使用大量模板,并传递迭代器而不是集合.如果你想要虚函数调用,那就不行了,因为除了vector没有虚拟析构函数之外,它没有任何虚函数.
如果你真的想要使用标准容器进行动态多态(也就是说,你想做
vector<int> *ptr = new myvec(1);),那么你就进入了"你不应该"的领域.标准库无法真正帮助您.