你不能从std :: vectorinheritance

好吧,这真的很难承认,但我现在有一个强大的诱惑,从std::vectorinheritance。

我需要大约10个定制的vectoralgorithm,我希望它们是vector的直接成员。 但是,我自然也想拥有std::vector接口的其余部分。 那么,作为一个守法的公民,我的第一个想法是在MyVector类中有一个std::vector成员。 但是,我将不得不手动提供所有的std :: vector的接口。 键入的太多了。 接下来,我想到了私有inheritance,所以我不会using std::vector::member方法,而是在公共部分using std::vector::member 。 实际上这也很乏味。

在这里,我真的认为我可以简单地从std::vector公开inheritance,但是在文档中提供了一个警告,这个类不应该被多态使用。 我认为大多数开发人员都有足够的能力去理解这个不应该被多态地使用。

我的决定是绝对无理的吗? 如果是这样,为什么? 你可以提供一个替代scheme,其他成员实际上是成员,但不涉及重新input所有的vector接口? 我怀疑,但如果可以的话,我只会很开心。

此外,除了一些白痴可以写类似的事实

 std::vector<int>* p = new MyVector 

使用MyVector有没有其他现实的危险? 通过说现实我放弃像想象一个函数,需要一个指针向量…

那么,我已经说明了我的情况。 我犯罪了。 现在是由你来原谅我或不:)

实际上, std::vector公有inheritance没有任何问题。 如果你需要这个,就这样做。

如果真的有必要,我会build议你这样做。 只有当你不能用自由函数做你想做的事时(例如应该保持某种状态)。

问题是MyVector是一个新的实体。 这意味着一个新的C ++开发者在使用它之前应该知道它到底是什么。 std::vectorMyVector什么MyVector ? 哪一个更适合在这里和那里使用? 如果我需要将std::vector移动到MyVector ? 我可以只使用swap()吗?

不要生产新的实体,只是为了使一些看起来更好。 这些实体(特别是这样的共同体)不会生活在真空中。 他们将生活在混杂的环境中,熵不断增加。

整个STL被devise成algorithm和容器是分开的

这导致了不同types的迭代器的概念:const迭代器,随机访问迭代器等。

因此,我build议你接受这个约定,并devise你的algorithm,使他们不会关心他们正在处理的容器是什么 – 他们只需要一个特定types的迭代器,他们需要执行它们操作。

另外,让我重新引导你们杰夫·阿特伍德的一些很好的评论

不公开从std :: vectorinheritance的主要原因是虚拟析构函数的缺失,它有效地阻止了你对后代的多态使用。 尤其是, 不允许 delete实际指向派生对象的std::vector<T>* (即使派生类不添加成员),但编译器通常不会警告您。

在这些条件下允许私有inheritance。 因此,我build议使用私有inheritance并从父项转发所需的方法,如下所示。

 class AdVector: private std::vector<double> { typedef double T; typedef std::vector<double> vector; public: using vector::push_back; using vector::operator[]; using vector::begin; using vector::end; AdVector operator*(const AdVector & ) const; AdVector operator+(const AdVector & ) const; AdVector(); virtual ~AdVector(); }; 

您应该首先考虑重构您的algorithm以从它们正在操作的容器types中进行抽象,并将它们留作免费的模板函数,正如大多数答复者所指出的那样。 这通常通过使algorithm接受一对迭代器而不是容器作为参数来完成。

如果你正在考虑这个问题,你显然已经杀死了你办公室的语言学生。 与他们在一起,为什么不只是做

 struct MyVector { std::vector<Thingy> v; // public! void func1( ... ) ; // and so on } 

这将回避所有可能出现的错误,可能会出现意外上传你的MyVector类,你仍然可以访问所有的vector操作只需添加一点点.v

你希望完成什么? 只是提供一些function?

C ++惯用的方法是只编写一些实现该function的免费函数。 机会是你真的不需要一个std :: vector,专门为你正在实现的function,这意味着你实际上通过尝试从std :: vectorinheritance来损失重用性。

我强烈build议你看一下标准的库和头文件,并思考它们是如何工作的。

我认为应该百分之百地盲目地遵循很less的规则。 这听起来像是你给了它很多的想法,并相信这是一个路要走。 所以 – 除非有人提出具体的理由不这样做 – 我认为你应该继续你的计划。

没有理由从std::vectorinheritance,除非你想创build一个不同于std::vector ,因为它以自己的方式处理std::vector的隐藏细节,或者除非有意识形态的原因,使用这种类的对象代替std::vector的。 然而,C ++标准的创build者并没有提供带有任何接口(以受保护成员的forms)的std::vector ,这样的inheritance类可以利用这些接口来以特定的方式改进向量。 事实上,他们没有办法想到任何可能需要扩展或微调额外实现的具体方面,所以他们不需要考虑为任何目的提供任何这样的接口。

第二个选项的原因可能只是意识形态,因为std::vector s不是多态的,否则不pipe是通过公共inheritance还是通过公共成员来暴露std::vector的公共接口都没有区别。 (假设你需要在你的对象中保留一些状态,所以你不能逃脱自由函数)。 在一个不太可靠的音符上,从意识形态的angular度来看,似乎std::vector s是一种“简单的想法”,所以在意识形态上不同可能类的对象forms的任何复杂性都是无用的。

如果你遵循良好的C ++风格,没有虚函数是不是问题,但切片 (请参阅https://stackoverflow.com/a/14461532/877329

为什么虚拟function的缺失不是问题? 因为一个函数不应该试图delete它接收到的任何指针,因为它没有它的所有权。 因此,如果遵循严格的所有权策略,则不需要虚拟析构函数。 例如,这总是错误的(有或没有虚拟析构函数):

 void foo(SomeType* obj) { if(obj!=nullptr) //The function prototype only makes sense if parameter is optional { obj->doStuff(); } delete obj; } class SpecialSomeType:public SomeType { // whatever }; int main() { SpecialSomeType obj; doStuff(&obj); //Will crash here. But caller does not know that // ... } 

相反,这将始终工作(有或没有虚拟析构函数):

 void foo(SomeType* obj) { if(obj!=nullptr) //The function prototype only makes sense if parameter is optional { obj->doStuff(); } } class SpecialSomeType:public SomeType { // whatever }; int main() { SpecialSomeType obj; doStuff(&obj); // The correct destructor *will* be called here. } 

如果对象是由工厂创build的,则工厂也应该返回一个指向正在工作的删除器的指针,因为工厂可能会使用自己的堆,所以应该使用该指针来代替delete 。 调用者可以获得它的share_ptrunique_ptrforms。 总之,不要delete你没有直接 new获得的东西。

实际上,如果您的派生类中没有任何数据成员,则不存在任何问题,即使在多态使用情况下也是如此。 如果基类和派生类的大小不同和/或你有虚函数(这意味着一个V表),你只需要一个虚析构函数。

但理论上:从C ++ 0x FCD中的[expr.delete]:在第一个替代(删除对象)中,如果要删除的对象的静态types与其dynamictypes不同,则静态types应为要删除的对象的dynamictypes的基类和静态types应该有一个虚拟析构函数或行为是未定义的。

但是,你可以私自从std :: vector中导出而不会出现任何问题。 我使用了以下模式:

 class PointVector : private std::vector<PointType> { typedef std::vector<PointType> Vector; ... using Vector::at; using Vector::clear; using Vector::iterator; using Vector::const_iterator; using Vector::begin; using Vector::end; using Vector::cbegin; using Vector::cend; using Vector::crbegin; using Vector::crend; using Vector::empty; using Vector::size; using Vector::reserve; using Vector::operator[]; using Vector::assign; using Vector::insert; using Vector::erase; using Vector::front; using Vector::back; using Vector::push_back; using Vector::pop_back; using Vector::resize; ... 

我最近还从std::vectorinheritance了,发现它非常有用,到目前为止我还没有遇到任何问题。

我的类是一个稀疏的matrix类,这意味着我需要存储我的matrix元素的地方,即在一个std::vector 。 我inheritance的原因是我有点懒得写接口到所有的方法,而且我通过SWIG将类接口到Python,在那里已经有良好的std::vector接口代码。 我发现将这个接口代码扩展到我的类比从头开始编写新的接口代码更容易。

我能看到的唯一的问题不是非虚拟的析构函数,而是一些我想重载的方法,比如push_back()resize()insert()等等。私有inheritance确实是一个很好的select。

谢谢!

是的,只要你小心不要做那些不安全的事情,这是安全的…我不认为我见过任何人使用新的载体,所以在实践中,你可能会很好。 但是,这不是在C ++中常见的习惯用法….

你能给出更多关于algorithm的信息吗?

有时候你最终只能用一种devise走下一条路,然后看不到你可能采取的其他path – 事实上,你声称需要用10个新的algorithm向我发出警钟 – 真的有10个通用一个向量可以实现的algorithm,还是你正在试图创build一个既是通用vector又包含应用程序特定函数的对象?

我当然不是说你不应该这样做,只是因为你提供的信息令人震惊,这使得我认为你的抽象可能有些问题,并且有更好的方法来实现你想。