获取向量< Derived *>进入期望向量< Base *>的函数
-
02-07-2019 - |
题
考虑这些课程。
class Base
{
...
};
class Derived : public Base
{
...
};
这个功能
void BaseFoo( std::vector<Base*>vec )
{
...
}
最后我的载体
std::vector<Derived*>derived;
我想将 derived
传递给函数 BaseFoo
,但编译器不允许我。如何在不将整个矢量复制到 std :: vector&lt; Base *&gt;
的情况下解决这个问题?
解决方案
vector&lt; Base *&gt;
和 vector&lt; Derived *&gt;
是不相关的类型,因此您无法执行此操作。这在C ++ FAQ 此处中有说明。
您需要将变量从 vector&lt; Derived *&gt;
更改为 vector&lt; Base *&gt;
并插入 Derived
对象进入它。
另外,为了避免不必要地复制 vector
,你应该通过const-reference传递它,而不是通过值:
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
函数。
其他提示
不是传递容器对象( vector&lt;&gt;
),而是传递 begin
和 end
迭代器,就像其他STL算法一样。接收它们的函数将被模板化,如果传入Derived *或Base *则无关紧要。
在具有可变容器的编程语言中会出现此问题。你不能把一袋可变的苹果作为一袋水果来传递,因为你不能确定别人没有把柠檬放入那袋水果中,之后它就不再是一袋苹果了。如果苹果袋不可变,将它作为一袋水果传递就可以了。搜索协方差/逆变。
一个选项是使用模板
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
缺点是实现必须在标题中,你会得到一些代码膨胀。最后将为每种类型实例化不同的函数,但代码保持不变。根据使用情况,这是一个快速而肮脏的解决方案。
编辑,我应该注意我们在这里需要模板的原因是因为我们正在尝试为其他几个海报所指出的不相关类型编写相同的代码。模板允许您解决这些确切的问题。我还更新了它以使用const引用。你也应该传递“沉重”的
,当你不需要副本时,像const引用的向量这样的对象通常你会从一个基本指针容器开始,而不是从另一个方向开始。
参加 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 );
如果您与第三方图书馆打交道,这是您唯一的希望,那么您可以这样做:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
否则,请使用其他一个建议来修复您的代码。
如果 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()
函数按值获取向量,它不能修改你传入的原始向量,所以我写的是不可能的。但是如果需要非const引用并使用 reinterpret_cast&lt; std :: vector&lt; Base *&gt;&amp;&gt;()
来传递 std :: vector&lt; Derived *&gt ;
,您可能无法获得所需的结果,并且您的程序可能会崩溃。
Java数组支持协变子类型,这需要Java 每次在数组中存储值时都要进行运行时类型检查。这也是不可取的。
它们是不相关的类型 - 你不能。