开发者

SmartPointer : cast between base and derived classes

开发者 https://www.devze.com 2023-02-24 05:27 出处:网络
Say you have a function like this : SmartPtr<A> doSomething(SmartPtr<A> a); And classes like this :

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 jus开发者_开发知识库t found something I believe ugly :

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

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


Instead of doing that, you can do this :

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

but you have to check if b is NULL.


For anyone stumbling across this decade old question while looking for how to do this, C++11 added dynamic_pointer_cast, static_pointer_cast, and const_pointer_cast to do exactly this. Now this problem is as simple as

shared_ptr<B> b=static_pointer_cast<B>(doSomething(foo));


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.


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

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

0

精彩评论

暂无评论...
验证码 换一张
取 消