好吧,这真的很难承认,但我确实有一个强烈的诱惑,从std::vector继承。

I need about 10 customized algorithms for vector and I want them to be directly members of the vector. But naturally I want also to have the rest of std::vector's interface. Well, my first idea, as a law-abiding citizen, was to have an std::vector member in MyVector class. But then I would have to manually reprovide all of the std::vector's interface. Too much to type. Next, I thought about private inheritance, so that instead of reproviding methods I would write a bunch of using std::vector::member's in the public section. This is tedious too actually.

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

我的决定是绝对不合理的吗?如果有,为什么?你能提供一个替代方案,这将有额外的成员实际上成员,但不会涉及重新键入所有矢量的接口?我很怀疑,但如果你能做到,我会很开心的。

而且,除了有些白痴能写出这样的东西

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

使用MyVector还有其他现实的危险吗?通过说现实,我放弃了一些东西,比如想象一个函数,它接受一个指向向量的指针…

我已经陈述了我的观点。我有罪。现在就看你是否原谅我了:)


当前回答

实际上,std::vector的公共继承并没有什么问题。如果你需要这个,就去做那个。

我建议只有在确实有必要的时候才这样做。只有当你不能用自由函数做你想做的事情时(例如,应该保持一些状态)。

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

不要仅仅为了让某些东西看起来更好而创造新的实体。这些实体(尤其是如此常见的实体)不会生活在真空中。它们将生活在熵不断增加的混合环境中。

其他回答

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

我的类是一个稀疏矩阵类,这意味着我需要在某个地方存储我的矩阵元素,即在std::vector中。我继承的原因是我有点太懒了,不愿意为所有的方法编写接口,而且我正在通过SWIG将类接口到Python,其中已经有std::vector的良好接口代码。我发现将这个接口代码扩展到我的类中要比从头开始编写一个新代码容易得多。

这种方法的唯一问题不是非虚析构函数,而是一些我想重载的其他方法,比如push_back()、resize()、insert()等。私人继承的确是一个不错的选择。

谢谢!

在这里,让我再介绍两种做你想做的事的方法。一种是包装std::vector的另一种方法,另一种是继承而不给用户破坏任何东西的方法:

让我添加另一种包装std::vector的方式,而无需编写大量的函数包装器。

#include <utility> // For std:: forward struct Derived: protected std::vector<T> { // Anything... using underlying_t = std::vector<T>; auto* get_underlying() noexcept { return static_cast<underlying_t*>(this); } auto* get_underlying() const noexcept { return static_cast<underlying_t*>(this); } template <class Ret, class ...Args> auto apply_to_underlying_class(Ret (*underlying_t::member_f)(Args...), Args &&...args) { return (get_underlying()->*member_f)(std::forward<Args>(args)...); } }; Inheriting from std::span instead of std::vector and avoid the dtor problem.

There is no reason to inherit from std::vector unless one wants to make a class that works differently than std::vector, because it handles in its own way the hidden details of std::vector's definition, or unless one has ideological reasons to use the objects of such class in place of std::vector's ones. However, the creators of the standard on C++ did not provide std::vector with any interface (in the form of protected members) that such inherited class could take advantage of in order to improve the vector in a specific way. Indeed, they had no way to think of any specific aspect that might need extension or fine-tune additional implementation, so they did not need to think of providing any such interface for any purpose.

The reasons for the second option can be only ideological, because std::vectors are not polymorphic, and otherwise there is no difference whether you expose std::vector's public interface via public inheritance or via public membership. (Suppose you need to keep some state in your object so you cannot get away with free functions). On a less sound note and from the ideological point of view, it appears that std::vectors are a kind of "simple idea", so any complexity in the form of objects of different possible classes in their place ideologically makes no use.

如果你正在考虑这个问题,那么你显然已经把办公室里的语言书呆子都干掉了。有了他们,为什么不直接做呢

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

这将避免所有可能出现的错误,可能会意外地向上转换你的MyVector类,你仍然可以访问所有的向量操作,只需添加一个小.v。

整个STL被设计成算法和容器是分开的。

这就产生了不同类型迭代器的概念:const迭代器、随机访问迭代器等等。

因此,我建议你接受这个约定,并以这样的方式设计你的算法,即它们不会关心它们正在处理的容器是什么——它们只需要特定类型的迭代器来执行它们的操作。

另外,让我把你引向杰夫·阿特伍德的一些精彩评论。