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

Posted

技术标签:

【中文标题】自动将指向派生类的指针列表转换为指向基类的指针列表【英文标题】:automatically convert list of pointers to derived class to list of pointers to base class 【发布时间】:2012-10-12 23:15:46 【问题描述】:

假设我有一个基类和派生类,以及一个接受指向基类的指针的 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 共享指针?

【问题讨论】:

【参考方案1】:

std::vector&lt;B*&gt; and std::vector&lt;A*&gt; 在技术上不相关。 C++ 不允许这样做。

一种方法...为什么不使用std::vector&lt;Base*&gt; 并将Derived 对象插入其中?这就是多态性、动态调度等的重点。

【讨论】:

【参考方案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'类对吧?我的意思是,拥有模板的全部意义在于拥有类型独立的编程。不是吗?【参考方案3】:

您可以从派生的基指针向量创建基指针的临时向量:

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)

【讨论】:

【参考方案4】:

您不能将vector&lt;B*&gt; 传递给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); );

【讨论】:

以上是关于自动将指向派生类的指针列表转换为指向基类的指针列表的主要内容,如果未能解决你的问题,请参考以下文章

将指向部分构造对象的指针转换为指向基类的指针是不是合法?

为啥C ++允许将指向基对象的指针转换为派生类的指针[重复]

从指向基类的指针调用派生类的复制构造?

声明指向基类和派生类的指针

向上强制转换和向下强制转换

为啥指向基类的派生类指针可以调用派生类成员函数? [复制]