SmartPointer:在基类和派生类之间进行转换

时间:2011-04-12 10:20:23

标签: c++ inheritance casting smart-pointers

假设你有这样的功能:

SmartPtr<A> doSomething(SmartPtr<A> a);

这样的课程:

class A { }
class B : public A { }

现在我这样做:

SmartPtr<A> foo = new B();
doSomething(foo);

现在,我想从SmartPtr<B>取回doSomething个对象。

SmartPtr<B> b = doSomething(foo); 

有可能吗?我需要做什么样的铸造?
现在,我刚发现了一些我认为丑陋的东西:

B* b = (B*)doSomething().get()

重要说明:我无法访问SmartPtrdoSomething()代码。

3 个答案:

答案 0 :(得分:8)

而不是这样做,你可以这样做:

B *b = dynamic_cast< B* >( doSomething.get() );

但你必须检查b是否为NULL。

答案 1 :(得分:-1)

您可以定义自己的SmartPtrCast模板功能,其功能如下:

template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT> &src)
{
    return SmartPtr<DestT>(static_cast<DestT*>(src.get()));
}

然后,你要做的就是从A到B优雅地演绎:

SmartPtr<B> b = SmartPtrCast<B>(doSomething(foo));

警告Emptor: 这只有在doSomething()返回的智能指针被引用到其他地方时才会起作用,并且当它超出范围时不会被销毁。从你的例子判断,情况确实如此,但它仍然没有那么优雅,应该注意的是两个指针不会共享它们的引用计数(所以如果其中一个被破坏,第二个将失去它的数据)。

更好的解决方案是分离其中一个指针(如果SmartPtr具有分离方法)。一个更好的解决方案(如果你没有分离方法或者你想共享引用计数)是使用包装类:

template <typename SrcT, typename DestT>
class CastedSmartPtr
{
private:
    SmartPtr<SrcT> ptr;
public:
    CastedSmartPtr(const SmartPtr<SrcT>& src)
    {
        ptr = src;
    }

    DestT& operator* () const
    {
        return *(static_cast<DestT*> >(ptr.get()));
    }

    DestT* operator->() const
    {
         return static_cast<DestT*> >(ptr.get());
    }

    DestT* get() const
    {
        return static_cast<DestT*> >(ptr.get());
    }
}

template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT>& src)
{
    return CastedSmartPtr<SrcT, DestT>(src);
}

这将在内部使用SmartPtr(因此引用计数已正确共享),并static_cast在内部使用DestT(不会影响性能)。如果要使用dynamic_cast,则只能在构造函数中执行一次,以避免不必要的开销。您可能还想为包装器添加其他方法,例如复制构造函数,赋值运算符,分离方法等。

答案 2 :(得分:-2)

SmartPtr<B> b = dynamic_cast<B*>(doSomething().get())

或者如果您的SmartPtr支持它,可能会像doSomething().dynamic_cast<B*>()那样。