c++ 将一个vector< Derived*>放入一个需要vector< Base*>的函数中

kognpnkq  于 2023-05-20  发布在  其他
关注(0)|答案(9)|浏览(139)

考虑这些类。

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

此函数

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

最后是我的矢量

std::vector<Derived*>derived;

我想将derived传递给函数BaseFoo,但编译器不允许。如何解决这个问题,而不将整个向量复制到std::vector<Base*>

muk1a3rh

muk1a3rh1#

vector<Base*>vector<Derived*>是不相关的类型,所以不能这样做。这在C++ FAQ中有解释。
您需要将变量从vector<Derived*>更改为vector<Base*>,并在其中插入Derived对象。
此外,为了避免不必要地复制vector,应该通过const-reference传递,而不是通过value传递:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

最后,为了避免内存泄漏,并使您的代码异常安全,请考虑使用设计用于处理堆分配对象的容器,例如:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

或者,更改向量以保存智能指针,而不是使用原始指针:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

在每种情况下,都需要相应地修改BaseFoo函数。

juzqafwq

juzqafwq2#

不传递容器对象(vector<>),而是像其他STL算法一样传递beginend迭代器。接收它们的函数将被模板化,传入Derived* 还是Base* 都没有关系。

pb3skfrl

pb3skfrl3#

此问题发生在具有可变容器的编程语言中。你不能把一袋易变的苹果当作一袋水果传来传去,因为你不能确定别人没有把一个柠檬放进那袋水果里,之后它就不再有资格成为一袋苹果了。如果这袋苹果不是可变的,那么把它当作一袋水果传来传去就可以了。搜索协方差/逆变。

vlju58qv

vlju58qv4#

一种选择是使用模板

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

缺点是实现必须在头文件中,您将得到一点代码膨胀。最后,您将为每种类型示例化不同的函数,但代码保持不变。根据使用情况,这是一个快速而肮脏的解决方案。
编辑,我应该注意到我们需要一个模板的原因是因为我们正在尝试为其他几个海报所指出的不相关类型编写相同的代码。模板允许您解决这些确切的问题。我还更新了它以使用const引用。当你不需要一个副本时,你也应该通过常量引用来传递“重”对象,比如一个向量,这基本上总是如此。

wyyhbhjk

wyyhbhjk5#

通常你会从一个基类指针的容器开始,而不是相反。

koaltpgm

koaltpgm6#

如果你在和第三方库打交道,而这是你唯一的希望,那么你可以这样做:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

否则,使用其他建议之一修复代码。

wwwo4jvm

wwwo4jvm7#

从上面Matt Price的回答来看,如果你事先知道你想在函数中使用什么类型,你可以在头文件中声明函数模板,然后为这些类型添加显式的示例化:

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
xkrw2x1b

xkrw2x1b8#

如果std::vector支持你所要求的,那么就有可能在不使用任何类型转换的情况下击败C类型系统(编辑:ChrisN的C FAQ Lite链接也讨论了同样的问题):

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!

由于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。这也是不期望的。

mqkwyuun

mqkwyuun9#

他们是不相关的类型-你不能。

相关问题