C++ 你不能从 std::vector 继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4353203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thou shalt not inherit from std::vector
提问by Armen Tsirunyan
Ok, this is really difficult to confess, but I do have a strong temptation at the moment to inherit from std::vector
.
好吧,这真的很难坦白,但我此刻确实有很强的诱惑力要继承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.
我需要大约 10 个自定义向量算法,我希望它们直接成为向量的成员。但自然我也想拥有其余std::vector
的界面。嗯,作为一个守法公民,我的第一个想法是std::vector
在MyVector
班上有一个成员。但随后我将不得不手动重新提供所有 std::vector 的接口。打字太多了。接下来,我想到了私有继承,这样我就不会重新提供方法,而是using std::vector::member
在公共部分写一堆's。这其实也很乏味。
And here I am, I really do think that I can simply inherit publicly from std::vector
, but provide a warning in the documentation that this class should not be used polymorphically. I think most developers are competent enough to understand that this shouldn't be used polymorphically anyway.
在这里,我确实认为我可以简单地从 公开继承std::vector
,但在文档中提供警告,不应以多态方式使用此类。我认为大多数开发人员都足以理解无论如何都不应该多态地使用它。
Is my decision absolutely unjustifiable? If so, why? Can you provide an alternative which would have the additional members actuallymembers but would not involve retyping all of vector's interface? I doubt it, but if you can, I'll just be happy.
我的决定绝对不合理吗?如果是这样,为什么?你能提供一个替代方案,让额外的成员实际上是成员,但不涉及重新输入所有 vector 的界面吗?我对此表示怀疑,但如果可以,我会很高兴。
Also, apart from the fact that some idiot can write something like
此外,除了一些白痴可以写出类似的东西
std::vector<int>* p = new MyVector
is there any other realisticperil in using MyVector? By saying realistic I discard things like imagine a function which takes a pointer to vector ...
使用 MyVector是否还有其他现实危险?通过说现实,我放弃了想象一个函数,它需要一个指向向量的指针......
Well, I've stated my case. I have sinned. Now it's up to you to forgive me or not :)
好吧,我已经陈述了我的情况。我犯罪了。现在由你决定是否原谅我:)
采纳答案by Stas
Actually, there is nothing wrong with public inheritance of std::vector
. If you need this, just do that.
实际上,std::vector
.的公共继承并没有什么问题。如果你需要这个,那就去做吧。
I would suggest doing that only if it is reallynecessary. Only if you can't do what you want with free functions (e.g. should keep some state).
我建议只有在确实有必要时才这样做。只有当你不能用自由函数做你想做的事情时(例如应该保持一些状态)。
The problem is that MyVector
is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector
and MyVector
? Which one is better to use here and there? What if I need to move std::vector
to MyVector
? May I just use swap()
or not?
问题是这MyVector
是一个新实体。这意味着新的 C++ 开发人员在使用它之前应该知道它到底是什么。std::vector
和 和有MyVector
什么区别?哪一个更适合在这里和那里使用?如果我需要移动std::vector
到MyVector
?我可以使用swap()
还是不使用?
Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.
不要仅仅为了让某些东西看起来更好而产生新的实体。这些实体(尤其是如此常见的实体)不会生活在真空中。它们将生活在熵不断增加的混合环境中。
回答by Kos
The whole STL was designed in such way that algorithms and containers are separate.
整个 STL 的设计方式是算法和容器是分开的。
This led to a concept of different types of iterators: const iterators, random access iterators, etc.
这导致了不同类型迭代器的概念:常量迭代器、随机访问迭代器等。
Therefore I recommend you to accept this convention and design your algorithms in such way that they won't care about what is the container they're working on- and they would only require a specific type of iterator which they'd need to perform their operations.
因此,我建议您接受此约定并以这样的方式设计您的算法,即他们不会关心他们正在处理的容器是什么- 他们只需要一种特定类型的迭代器来执行他们的操作。
Also, let me redirect you to some good remarks by Jeff Attwood.
另外,让我将您引向 Jeff Attwood 的一些精彩评论。
回答by Basilevs
The main reason for not inheriting from std::vector
publicly is an absence of a virtual destructor that effectively prevents you from polymorphic use of descendants. In particular, you are not allowedto delete
a std::vector<T>*
that actually points at a derived object (even if the derived class adds no members), yet the compiler generally can't warn you about it.
不从std::vector
public继承的主要原因是缺少虚拟析构函数,这有效地阻止了您对后代的多态使用。特别是,你都不准到delete
一个std::vector<T>*
在派生类对象(即使在派生类中没有增加成员),实际点,但编译器一般不能向您发出警告。
Private inheritance is allowed under these conditions. I therefore recommend using private inheritance and forwarding required methods from the parent as shown below.
在这些条件下允许私有继承。因此,我建议使用私有继承并从父级转发所需的方法,如下所示。
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();
};
You should first consider refactoring your algorithms to abstract the type of container they are operating on and leave them as free templated functions, as pointed out by majority of answerers. This is usually done by making an algorithm accept a pair of iterators instead of container as arguments.
正如大多数回答者所指出的那样,您应该首先考虑重构您的算法以抽象它们正在操作的容器类型,并将它们保留为免费的模板化函数。这通常是通过让算法接受一对迭代器而不是容器作为参数来完成的。
回答by Crashworks
If you're considering this, you've clearly already slain the language pedants in your office. With them out of the way, why not just do
如果您正在考虑这一点,那么您显然已经杀死了办公室里的语言学究。有了他们,为什么不直接做
struct MyVector
{
std::vector<Thingy> v; // public!
void func1( ... ) ; // and so on
}
That will sidestep all the possible blunders that might come out of accidentally upcasting your MyVector class, and you can still access all the vector ops just by adding a little .v
.
这将避免因意外向上转换 MyVector 类而可能出现的所有可能的错误,并且您仍然可以通过添加一点.v
.
回答by Karl Knechtel
What are you hoping to accomplish? Just providing some functionality?
你希望完成什么?只是提供一些功能?
The C++ idiomatic way to do this is to just write some free functions that implement the functionality. Chances are you don't really require a std::vector, specificallyfor the functionality you're implementing, which means you're actually losing out on reusability by trying to inherit from std::vector.
执行此操作的 C++ 惯用方法是仅编写一些实现该功能的免费函数。机会是你不真正需要一个std ::向量,专门为你实现这意味着你通过的std ::矢量试图继承重用性,实际上失去了功能。
I would strongly advise you to look at the standard library and headers, and meditate on how they work.
我强烈建议您查看标准库和头文件,并思考它们是如何工作的。
回答by NPE
I think very few rules should be followed blindly 100% of the time. It sounds like you've given it quite a lot of thought, and are convinced that this is the way to go. So -- unless someone comes up with good specificreasons not to do this -- I think you should go ahead with your plan.
我认为很少有规则应该在 100% 的情况下盲目遵循。听起来您已经考虑了很多,并且确信这是要走的路。所以——除非有人提出不这样做的具体理由——我认为你应该继续你的计划。
回答by Evgeniy
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 specificaspect that might need extension or fine-tune additional implementation, so they did not need to think of providing any such interface for any purpose.
没有理由继承 fromstd::vector
除非一个人想要创建一个与 不同的类std::vector
,因为它以自己的方式处理std::vector
定义的隐藏细节,或者除非一个人有意识形态上的原因使用这样的类的对象来代替std::vector
的。但是,C++ 标准的创建者没有提供std::vector
任何接口(以受保护成员的形式),此类继承类可以利用这些接口以特定方式改进向量。事实上,他们没有办法考虑可能需要扩展或微调额外实现的任何特定方面,因此他们不需要考虑为任何目的提供任何此类接口。
The reasons for the second option can be only ideological, because std::vector
s 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::vector
s 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.
第二种选择的原因只能是意识形态上的,因为std::vector
s 不是多态的,否则无论您std::vector
通过公共继承还是通过公共成员资格公开的公共接口都没有区别。(假设你需要在你的对象中保留一些状态,这样你就无法摆脱自由函数的束缚)。在不太健全的音符上,从意识形态的角度来看,似乎std::vector
s 是一种“简单的想法”,因此任何以不同可能类别的对象形式在意识形态上占据其位置的复杂性都毫无用处。
回答by hmuelner
In practical terms: If you do not have any data members in your derived class, you do not have any problems, not even in polymorphic usage. You only need a virtual destructor if the sizes of the base class and the derived class are different and/or you have virtual functions (which means a v-table).
实际上:如果您的派生类中没有任何数据成员,那么您就没有任何问题,甚至在多态使用方面也没有问题。如果基类和派生类的大小不同和/或您有虚拟函数(这意味着一个 v 表),您只需要一个虚拟析构函数。
BUT in theory:From [expr.delete] in the C++0x FCD: In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
但是理论上:来自C++0x FCD中的[expr.delete]:在第一种选择(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除的对象的动态类型和静态类型的基类应具有虚拟析构函数或行为未定义。
Butyou can derive privately from std::vector without problems. I have used the following pattern:
但是您可以毫无问题地从 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;
...
回答by user877329
If you follow good C++ style, the absence of virtual function is not the problem, but slicing(see https://stackoverflow.com/a/14461532/877329)
如果你遵循良好的 C++ 风格,虚函数的缺失不是问题,而是切片(参见https://stackoverflow.com/a/14461532/877329)
Why is absence of virtual functions not the problem? Because a function should not try to delete
any pointer it receives, since it does not have an ownership of it. Therefore, if following strict ownership policies, virtual destructors should not be needed. For example, this is always wrong (with or without virtual destructor):
为什么没有虚函数不是问题?因为函数不应该尝试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
// ...
}
In contrast, this will always work (with or without virtual destructor):
相比之下,这将始终有效(有或没有虚拟析构函数):
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.
}
If the object is created by a factory, the factory should also return a pointer to a working deleter, which should be used instead of delete
, since the factory may use its own heap. The caller can get it form of a share_ptr
or unique_ptr
. In short, do not delete
anything you didn't get directlyfrom new
.
如果对象是由工厂创建的,工厂还应该返回一个指向工作删除器的指针,应该使用它而不是delete
,因为工厂可能使用自己的堆。调用者可以获得 ashare_ptr
或 的形式 unique_ptr
。简而言之,不要做delete
任何你没有直接从new
.
回答by jcoder
Yes it's safe as long as you are careful not to do the things that are not safe... I don't think I've ever seen anyone use a vector with new so in practice you'll likely be fine. However, it's not the common idiom in c++....
是的,只要您小心不要做不安全的事情,它就是安全的……我想我从未见过有人使用带有 new 的矢量,因此在实践中您可能会没事。但是,这不是 C++ 中的常见习语....
Are you able to give more information on what the algorithms are?
您能否提供有关算法的更多信息?
Sometimes you end up going down one road with a design and then can't see the other paths you might have taken - the fact that you claim to need to vector with 10 new algorithms rings alarm bells for me - are there really 10 general purpose algorithms that a vector can implement, or are you trying to make an object that is both a general purpose vector AND which contains application specific functions?
有时,您最终会在设计中走上一条路,然后看不到您可能采用的其他路径——事实上,你声称需要使用 10 个新算法进行矢量对我来说是警钟——真的有 10 个通用目的吗?向量可以实现的算法,或者您是否正在尝试制作一个既是通用向量又包含应用程序特定功能的对象?
I'm certainly not saying that you shouldn't do this, it's just that with the information you've given alarm bells are ringing which makes me think that maybe something is wrong with your abstractions and there is a better way to achieve what you want.
我当然不是说你不应该这样做,只是你提供的信息敲响了警钟,这让我觉得你的抽象可能有问题,有更好的方法来实现你的目标想。