自动将指向派生类的指针列表转换为指向基类的指针列表

4
假设我有一个基类和派生类,并且有一个函数接受一个指向基类的STL向量指针:
class A { public: int x; };

class B : public A { };

void foo(const vector<A*> &va) {
    for (vector<A*>::const_iterator it = va.begin(); it < va.end(); it++)
        cout << (*it)->x << endl;
}

有没有办法将指向派生类的指针列表传递给它?例如:
vector<B*> vb;
// ... add pointers to vb ...
foo(vb);

上述代码将导致以下编译错误:
error: could not convert ‘vb’ from ‘std::vector<B*>’ to ‘std::vector<A*>’

尽管B*可以转换为A*。

最后,如果有针对普通指针的解决方案,它是否也适用于boost共享指针?

4个回答

5

std::vector<B*>std::vector<A*>在技术上没有关联。C++不允许你这样做。

一个解决方法是...为什么不使用std::vector<Base*>,并将Derived对象插入其中呢?这就是多态、动态分派等的重点所在。


2
你可以从派生基指针的向量中创建临时的基指针向量:
std::vector<B*> bv;
foo(std::vector<A*>(bv.begin(), bv.end())); 

但是这需要foo接受const引用而不是像你的例子中的引用,这非常低效,需要内存分配和复制。
另一种更好的解决方案是将你的foo变成一个函数模板:
template <class T>
void foo(std::vector<T*>& v);

为确保foo仅用于派生自A的情况,请使用type_traits和SFINAE技术。请注意,您仅使用第一个参数调用foo,第二个参数仅用于消除不是从A派生的类型的函数模板(SFINAE):

#include <type_traits>

template <class T>
void foo(std::vector<T*>& av,
         // don't use this second param 
         typename std::enable_if<std::is_base_of<A,T>::value>::type* = 0)

2

正如@Science_Fiction之前所说,拥有一个指向基本类型的指针向量并将指向基本和派生类型的指针插入其中更加合理。但是如果您无法控制这些数组的创建,可以使用模板:

template <class T>
inline void foo(const vector<T*>& v)
{
    for (vector<T*>::const_iterator it = v.begin(); it < v.end(); ++it)
    {
        A* a = (A*) *it;
        cout << a->x << endl;
    }
}

为了让自己更清楚,这个方法既不属于Base类也不属于Derived类,对吗?我的意思是,使用模板的整个目的是进行类型无关的编程。是吗? - Recker

1

您不能将vector<B*>传递给foo,因为类型不兼容--即使B*可以隐式转换为A*也没有关系。

你可以做的是创建一个新的正确类型的vector,例如:

vector<B*> vb;
// ... add pointers to vb ...

vector<A*> va(vb.size());
std::transform(vb.begin(), vb.end(), va.begin(),
               [] (B* p) { return static_cast<A*>(p); });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接