SmartPointer : cast between base and derived classes

荒凉一梦 提交于 2019-12-23 15:01:26

问题


Say you have a function like this :

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

And classes like this :

class A { }
class B : public A { }

And now I do this :

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

Now, I would like to get back a SmartPtr<B> object from doSomething.

SmartPtr<B> b = doSomething(foo); 

Is it possible ? What kind of casting do I have to do ?
Right now, I just found something I believe ugly :

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

Important notes : I do not have any access to SmartPtr and doSomething() code.


回答1:


Instead of doing that, you can do this :

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

but you have to check if b is NULL.




回答2:


You can define your own SmartPtrCast template function which does something like:

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

Then, all you have to do cast gracefully from A to B is:

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

Caveat Emptor: This will only work if the smart pointer returned by doSomething() is referenced somewhere else, and is not destroyed when it goes out of scope. Judging by your example, this is the case, but it's still not as graceful, and it should be noted that the two pointers won't share their reference counting (so if one of them gets destroyed, the second will lose its data).

A better solution is either to detach one of the pointers (if SmartPtr has a detach method). An even better solution (if you don't have a detach method or if you want to share the reference count) is to use a wrapper class:

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);
}

This will use a SmartPtr internally (so reference count is properly shared) and static_cast it to internally to DestT (with no performance impact). If you want to use dynamic_cast, you can do it only once, in the constructor, to avoid unnecessary overhead. You may also want to add additional method to the wrapper such as copy constructor, assignment operator, detach method, etc.




回答3:


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

or perhaps something like doSomething().dynamic_cast<B*>() if your SmartPtr supports it.



来源:https://stackoverflow.com/questions/5633695/smartpointer-cast-between-base-and-derived-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!