【问题标题】:cast list<A*> to list<B*> where B inherits A将 list<A*> 转换为 list<B*>,其中 B 继承 A
【发布时间】:2014-07-16 09:00:42
【问题描述】:

我有一个函数

void doSomething(list<A*> list1, list<A*> list2)

和类

class B : A  
class C : A

有没有像这样直接调用我的函数的方法

void doSomething(list<B*> listOfB, list<C*> listOfC)

或者我必须像手动包装它

void doSomething(list<B*> listOfB, list<C*> listOfC) {
  list<A*> l1;
  list<A*> l2;

  for (B* b : listOfB)
    l1.insert(b);

  for (C* c : listOfC)
    l2.insert(c);

  doSomething(l1, l2); //calling the function taking supertype
}

我尝试将list&lt;B*&gt; 转换为list&lt;A*&gt; 失败,我的猜测是由于模板专业化,编译器认为list&lt;B*&gt;list&lt;A*&gt; 不相关,但是B 继承了A。

有人可以确认这一点,或者用不同的方法来解决这个问题吗?

【问题讨论】:

  • 没错。它们是不同的类型,它们之间没有转换机制。
  • 您应该将列表声明为list&lt;A*&gt;,无论您使用B* 还是C* 填充它,您都将其作为参数传递。对于多态类型,无论实际类型如何,始终使用基指针/引用。
  • 说我疯了,但我只想把它做成一个函数模板。
  • 重写你的算法,让它们根据迭代器而不是容器工作?
  • 您可以通过 iterator-constructor 构造这些临时列表,但我个人更倾向于修改 doSomething 以仅采用四个 iteratoro 参数。如果 B 和 C 从 A 继承,那么 (*it)-&gt;Asomething() ,其中 AsomethingA 的成员(因此 BC)可能是一个合理的解决方案。

标签: c++ templates stl casting containers


【解决方案1】:

您的直觉(以及 juanchopanza 的评论)是正确的 - 列表是完全不相关的类型。

选项有:

  1. 首先在任何地方使用list&lt;A*&gt;,即使您知道动态类型是B*C*
  2. list&lt;A*&gt; 上编写一个包装器,它可以转换为正确的动态类型/从正确的动态类型转换 - 这相当于 Java 泛型中的(取消)装箱行为
  3. doSomething重写为函数模板,其唯一的约束是类型可转换

    template <typename Sequence1, typename Sequence2>
    void doSomething(Sequence1 &x, Sequence2 &y) {
      // require only that *x.begin() is convertible with *y.begin(), etc.
    }
    

    我也同意 Kerrek 的建议,即应该使用迭代器,但这并不会显着改变类型要求 - 您只需获得两个迭代器类型参数而不是两个容器类型参数

【讨论】:

  • 感谢大家的快速回答,绝对有用。我想我会去找一个函数模板,看看如何将模板类型限制为 A 的子类。
  • 您应该能够将std::is_base_ofenable_ifstatic_assert 一起使用。尽管错误消息不是很好,但允许进行鸭式输入通常很有用。
  • 是的,我检查了this post,谢谢@Useless :)
猜你喜欢
  • 2019-10-23
  • 2011-12-03
  • 2021-04-03
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 2012-07-31
  • 1970-01-01
  • 2019-12-09
相关资源
最近更新 更多