【问题标题】:how to convert between a container of a derived type to a container of a base type如何将派生类型的容器转换为基类型的容器
【发布时间】:2012-08-14 14:30:25
【问题描述】:

我有一个 C++03 应用程序,它的类包含一个类型的单个实例,我试图在派生类型的持有者和基类型的持有者之间进行转换。例如:

class B { public: virtual ~B() { }; };

class A : public B { };

template< typename T >
class Container
{
public:
    explicit Container( T* obj ) : obj_( obj ) { };
    Container( const Container< T >& ref ) : obj_( ref.obj_ ) { };

    template< typename U > operator Container< U >() { 
        return Container< U >( obj_ );
    };

private:
    T* obj_;
};

这很好用:

int main()
{
    Container< A > a_ref( new A() );
    Container< B > b_ref = a_ref;
    return 0;
}

这给了我错误invalid initialization of reference of type ‘Container&lt;B&gt;&amp;’ from expression of type ‘Container&lt;A&gt;’

void Foo( Container< B >& cb ) { }

int main()
{
    Container< A > a_ref( new A() );
    Foo( a_ref );
    return 0;
}

这给了我错误error: invalid initialization of non-const reference of type ‘Container&lt;B&gt;&amp;’ from a temporary of type ‘Container&lt;B&gt;’L

int main()
{
    Container< A > a_ref( new A() );
    Foo( static_cast< Container< B > >( a_ref ) );
    return 0;
}

如何将Container&lt; A &gt; 类型传递给需要Container&lt; B &gt; 类型的函数?我需要先复制对象吗?

【问题讨论】:

  • 是的,您必须复印一份。即使 A 是从 B 派生的,一个容器也不是从另一个容器派生的。它们是完全不同的类型。
  • a_ref 不是...参考(参考)。

标签: c++ templates constructor type-conversion


【解决方案1】:

添加另一个构造函数:

template <typename U>
Container(Container<U> const & ref,
          typename std::enable_if<std::is_base_of<T, U>::value, int>::type = 0)
: obj_(ref.obj_)
{ }

我添加了enable_if 部分以确保这个新的构造函数模板仅在U 类型实际上派生自T 时才参与重载决议。

【讨论】:

  • 我认为你不需要enable_if,正常的 SFINAE 应该会处理它。
  • @MichaelAnderson:想想std::is_constructible&lt;Container&lt;A&gt;, Container&lt;B&gt;&gt;
  • @KerrekSB - 谢谢,但std::enable_if 是 C++11。这是一个 C++03 项目。
  • @PaulH:enable_if 是您可以轻松编写自己的最简单的单行代码。
  • @PaulH:说Foo(Container&lt;B&gt; const &amp; cb)。您不能将临时值绑定到非常量左值引用。
【解决方案2】:

Container&lt;A&gt;Container&lt;B&gt; 是完全不同的类。

您可以使用container_cast&lt;T&gt;(U) 之类的东西将Container&lt;A&gt; 转换为Container&lt;B&gt;

container_cast 将构造另一个Container&lt;T&gt;,方法是采用obj_ Container&lt;U&gt; 并将obj_ 转换为T*

【讨论】:

  • 尽管在某些特定情况下(您需要只读访问权限),强制转换可能是安全的。这也取决于容器类型:vectors 自然不适用,但listmap 等(即为每个元素分配单独节点的容器)。另外,这取决于实现细节。特别是如果容器的节点首先声明其私有变量,最后声明您的类型的对象 - 类型转换 is 安全。
  • 是的,因为问题只提到了一个T* obj_,这就是我在回答中采用这种方式的原因。但是我从来没有练习过,而且我也从来没有遇到过这种情况。但这样它应该可以工作。我不认为这是一个糟糕的设计。
  • 据我了解,Foo( container_cast&lt; B &gt;( a_ref ) ); 会给我一个关于引用由 container_cast 创建的临时对象的错误。除非你知道实现Container&lt;T&gt;&amp; container_cast( Container&lt;U&gt;&amp; )的方法。
  • 您可以设计container_cast 以返回另一个Container,将内部obj_ 复制到其中并进行转换。
  • @PaulH:我的意思是这样的ideone.com/byt3C。你为什么故意将临时参数传递给参考参数?
【解决方案3】:

不要使用容器,而是使用迭代器对,它可以很好地转换为基类。解决问题,一次性清理代码。


编辑:在提供更多信息后,我将答案更改为:

使用boost::shared_ptr

【讨论】:

  • 我不认为容器在这种情况下指的是任何类似于 STL 容器的东西(我一开始误读了这个)——但纯粹是另一个类的单个实例的持有者——这个迭代器是不合适的.
  • 类的单个实例的持有者是std::unique_ptrboost::scoped_ptrstd/boost::shared_ptr。它不是一个容器。
  • @MichaelAnderson - 你是对的。我将修改问题以使其更清楚。
  • @rubenvb - 是的,它来自第 3 方库,在概念上类似于 boost::shared_ptr
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 2016-11-06
相关资源
最近更新 更多