用于操作基础/派生对象容器的函数
考虑以下带有数组的算法:
class MyType;
{
// some stuff
}
class MySubType:MyType
{
// some stuff
}
void foo(MyType** arr, int len)
{
for (int i = 0;i<len;i++)
// do something on arr[i]->
}
void bar()
{
MySubType* arr[10];
// initialize all MySubType*'s in arr
foo(&arr, 10);
}
这里没有什么太奇特的。 我的问题是 - 如何使用模板来做到这一点?
void foo(std::vector<MyType>& s)
{
std::vector<MyType>::iterator i;
for (i = s.begin(); i != s.end(); i++)
// do stuff on *i
}
所以,在 bar 中,我不能这样做:
void bar()
{
std::vector<MySubType> s;
foo(s); // compiler error
}
错误:类型 std::vector
来自 std::vector
有什么方法可以做这样的事情吗?
基本上,如果有办法做到这一点:
std::vector<MySubType> s;
std::vector<MyType>& t = s;
我会很高兴......
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这可能会解决您的问题
This might fix your problem
扩展 kuoson 的答案,即惯用的 C++ 风格是将迭代器传递给函数而不是容器。
To expand on kuoson's answer, the idiomatic C++ style is to pass iterators to a function rather than containers.
这就是问题所在 - 如果 s 和 t 指向同一个对象,那么什么会阻止您将
MyOtherSubType
(与 MySubType 无关)放入 t 中? 这将使 s 包含不是 MySubType 的对象。 我不知道有任何类型安全的编程语言可以让你做到这一点。 如果允许的话,想象一下我们会遇到的问题:由于 t 和 s 是不同名称下的完全相同的对象,因此 s[0] 处的元素不是 MySubType。 巨大的问题 - 我们永远无法确定我们的向量是否包含它们应该包含的类型! 因此,编译不允许它。
Here's the problem with this - if s and t point to the same object, what's to stop you putting
MyOtherSubType
(not related to MySubType) into into t? That would make s contain objects that are not MySubType. I don't know of any type-safe programming language that lets you do this. If it were allowed, imagine the problems we'd have:Since t and s are exactly the same object under different names, the element at s[0] is something that is not MySubType. Huge problem - we could never be sure that our vectors contained the types they are supposed to! Thus, the compiled disallows it.
既然你说,“这里没什么太花哨的”,我不确定你是否意识到这一点:
你的原始代码已损坏; 或者如果你幸运的话,它现在可能不会被破坏,但它非常脆弱,一旦有人做了比查看
MySubType
类更多的事情,它就会被破坏。问题是您将
MyType*
传递给foo()
,但它实际上指向MySubType
数组。 如果MySubType
对象恰好比MyType
对象大(如果您向派生类添加了任何内容,则很可能如此),则在foo()
函数将不正确。这是派生类对象数组的严重且经典的陷阱之一。
Since you say, "Nothing too fancy here", I'm not sure you realize this:
Your original code is broken; or if you're lucky it might not be broken right now, but it's quite fragile and will break as soon as someone does something more than look at the
MySubType
class.The problem is that you're passing a
MyType*
tofoo()
but it really points to an array ofMySubType
. If aMySubType
object happens to be larger than aMyType
object (which is pretty likely if you've added anything to the derived class), then the pointer arithmetic done in thefoo()
function will be incorrect.This is one of the serious and classic pitfalls of arrays of derived class objects.
如果您想在单个向量中存储多个不同
MyType
派生类型的对象(我怀疑您这样做,尽管对于这个特定示例来说这不是必需的),您将需要使用std::vector
而不是std::vector
。 此建议类似于 Michael Burr 针对您的原始指针代码提出的建议。这确实有一个不幸的副作用,您无法将
std::vector
隐式转换为std::vector
来调用foo()
与。 但转换代码并不太繁重:或者,只需让
bar()
从一开始就使用std::vector
即可。If you want to store objects of multiple different
MyType
-derived types inside a single vector (as I suspect you do, although that's not necessary for this particular example), you'll need to use astd::vector<MyType*>
instead ofstd::vector<MyType>
. This suggestion is analogous to that proposed by Michael Burr for your original pointer code.This does have the unfortunate side-effect that you cannot implicitly convert a
std::vector<MySubType*>
to astd::vector<MyType*>
to callfoo()
with. But the conversion code is not too onerous:Or, just have
bar()
use astd::vector<MyType*>
from the beginning.C++ 不支持模板类型的协变,这与 C# 目前不支持的程度相同,原因大致相同。 如果您想这样做,最好使您的向量在公共接口类型(指向该类型的指针)上模板化,并使函数 foo 接受该类型的向量。
C++ does not support covariance on template types, any more than C# currently does, much for the same reasons. If you want to do this, it is best to make your vector be templatised on a common interface type (of pointers to that type), and make the function foo accept a vector of that type.
不幸的是,没有。 不同的模板专业化被视为不同的类; 您无法在
std::vector
和std::vector
之间进行转换。您可以将 foo() 的“do stuff”公共位拆分为一个单独的函数,并对每个向量进行单独的循环(或者可能使用 std::foreach)。
Unfortunately, there isn't. Different template specialisations are considered different classes; you can't convert between
std::vector<MyType>
andstd::vector<MySubType>
.You could split the "do stuff" common bit of
foo()
into a separate function and have a separate loop over each vector (or possibly usestd::foreach
).使用 boost (用于智能指针):
Using boost (for smart pointer):
如果我知道这些 foobars 背后的真正代码是什么,那么也许我会知道得更好,但是 STL 中是否已经有解决您问题的方法了?
只需将“do stuff on *i”代码放入函数或函子中即可:
如果您担心发送两个参数而不是一个参数,那么好吧,也许您可以执行以下操作:
然后像这样调用 for_each :
If I'd know what's the real code behind those foobars then maybe I'd know better, but isn't there already a solution for your problem in the STL?
Just put your "do stuff on *i" code in a function or a functor:
If you're bothered about sending away two parameters instead of one, then ok, maybe you can do something like:
Then call for_each like so: