class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
void pushStuff(std::vector<Base*>& vec) {
vec.push_back(new Derived2);
vec.push_back(new Base);
}
...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!
9条答案
按热度按时间muk1a3rh1#
vector<Base*>
和vector<Derived*>
是不相关的类型,所以不能这样做。这在C++ FAQ中有解释。您需要将变量从
vector<Derived*>
更改为vector<Base*>
,并在其中插入Derived
对象。此外,为了避免不必要地复制
vector
,应该通过const-reference传递,而不是通过value传递:最后,为了避免内存泄漏,并使您的代码异常安全,请考虑使用设计用于处理堆分配对象的容器,例如:
或者,更改向量以保存智能指针,而不是使用原始指针:
或
在每种情况下,都需要相应地修改
BaseFoo
函数。juzqafwq2#
不传递容器对象(
vector<>
),而是像其他STL算法一样传递begin
和end
迭代器。接收它们的函数将被模板化,传入Derived* 还是Base* 都没有关系。pb3skfrl3#
此问题发生在具有可变容器的编程语言中。你不能把一袋易变的苹果当作一袋水果传来传去,因为你不能确定别人没有把一个柠檬放进那袋水果里,之后它就不再有资格成为一袋苹果了。如果这袋苹果不是可变的,那么把它当作一袋水果传来传去就可以了。搜索协方差/逆变。
vlju58qv4#
一种选择是使用模板
缺点是实现必须在头文件中,您将得到一点代码膨胀。最后,您将为每种类型示例化不同的函数,但代码保持不变。根据使用情况,这是一个快速而肮脏的解决方案。
编辑,我应该注意到我们需要一个模板的原因是因为我们正在尝试为其他几个海报所指出的不相关类型编写相同的代码。模板允许您解决这些确切的问题。我还更新了它以使用const引用。当你不需要一个副本时,你也应该通过常量引用来传递“重”对象,比如一个向量,这基本上总是如此。
wyyhbhjk5#
通常你会从一个基类指针的容器开始,而不是相反。
koaltpgm6#
如果你在和第三方库打交道,而这是你唯一的希望,那么你可以这样做:
否则,使用其他建议之一修复代码。
wwwo4jvm7#
从上面Matt Price的回答来看,如果你事先知道你想在函数中使用什么类型,你可以在头文件中声明函数模板,然后为这些类型添加显式的示例化:
xkrw2x1b8#
如果
std::vector
支持你所要求的,那么就有可能在不使用任何类型转换的情况下击败C类型系统(编辑:ChrisN的C FAQ Lite链接也讨论了同样的问题):由于
BaseFoo()
函数按值接受向量,它不能修改传入的原始向量,所以我写的内容是不可能的。但是如果它接受一个非常量引用,而你使用reinterpret_cast<std::vector<Base*>&>()
来传递你的std::vector<Derived*>
,你可能不会得到你想要的结果,你的程序可能会崩溃。Java数组支持covariant subtyping,这要求Java支持do a runtime type check every time you store a value in an array。这也是不期望的。
mqkwyuun9#
他们是不相关的类型-你不能。