Topic: How do I downcast class-encapsulated pointers?


Author: jas <jas@sdiusa.com>
Date: 8 Mar 1995 22:49:19 GMT
Raw View
I am encapsulating a pointer functionality within simple class
template, Ref<T>.

I can't seem to cast between a Ref<Derived> and a Ref<Base>.

>|> Here is the implementation that I have so far.
>|>
>|>template <class T> class Ref {
>|>public:
>|>    Ref(T* p = 0)    {   p_ = p;  if ( p_ ) p_->ref();  }
>|>    Ref(const Ref<T>& r)
>|>        {   p_ = r.p_;   if ( p_ ) p_->ref();    }
>|>    ~Ref()
>|>        {   if ( p_ )  p_->unref();   }
>|>
>|>    Ref<T> & operator=( const Ref<T> & r )
>|>        {  if ( p_ )  p_->unref( );
>|>           p_ = r.p_;
>|>           if ( p_ )  p_->ref();
>|>           return *this;         }
>|>
>|>    Ref<T> & operator=( T * r )


( I know its ugly looking code, but I had to cut it down to get
news post to accept it. )


>It seems questionable to allow an assignment from a pointer
> on the left hand side.  This is equivalent to:
>  AnyClass o;
>       AnyClass *p;
>       o = p;
>That does not seem proper.


That is not what it is doing.  Ref<T> and T * should seem to be
equivalent.  T is one type, and Ref<T> should seem to be a pointer
to that type it. We should be able to assign a Ref<T> to a T *.
Ref<T> is supposed to encapsulate a pointer.



>|>class SDIRefCounter {
>|>public:
>|>    SDIRefCounter() { refCount_ = 0; }
>|>    virtual ~SDIRefCounter() { }
>|>
>|>    void ref()   {  refCount_++;   }
>|>    void unref() {  if ( --refCount_ <= 0 )  delete this;  }
>|>private:
>|>    unsigned refCount_;
>|>};
>|>
>|>class Base : public SDIRefCounter  { };
>|>
>|>class Derived: public Base  { };

>|> I can't directly convert Ref<Derived> into Ref<Base> or cast
>|> Ref<Base> into a Ref<Derived> (when I know it is a derived!)
>|> as I would if Ref<T> were a pointer instead.

>The problem you are having is that Ref<Derived> is not a subclass
>of Ref<Base>.

Yep.  That is the problem that I want to be able to get around.

Actually, I would just like to make the Ref<T> look like a pointer.
I want to be able to pass a Ref<Derived> to a function that takes
a Ref<Base>,  I want to be able to cast a Ref<Base> into a
Ref<Derived>, ... basically full pointer functionality in Ref<T>.

Please, if any one has any ideas on this problem, let me know.

Thanks,
Stew

<< Thanks Bill!  The other stuff you commented on was helpful! >>

-------------------------------------
Name: Jim Stewart   E-mail: jas@sdiusa.com
Date:03/08/95   Time:09:15:04
-------------------------------------





Author: enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner)
Date: 06 Mar 1995 08:23:01 GMT
Raw View
I'll assume you creating a Derived-instance in 'testIt'.
Otherwise the downcasting would be an error. The direct way:

      Ref< Derived > derivedRef = (Derived*)( Base * ) baseRef;

A more general (and safer) solution would use sth. like

 template<class Base,class Sub>
 bool narrowRef(const Ref<Base>& baseRef,Ref<Sub>& subRef) {
  Base* base=baseRef;
  Sub* sp;

  if ((sp=dynamic_cast<Sub*>(base))) { subRef=sp; return true; }
  else return false;
 }

if your compiler supports RTTI and Base has a virtual member-function.

The 'testIt' function could be rewritten as:

void testIt( )
{
    Ref< Base > baseRef = new Derived;
    Ref< Derived > derivedRef;

    if (narrowRef(baseRef,derivedRef)) success();
    else cry4help();
}

 Enno




Author: jas <jas@sdiusa.com>
Date: 3 Mar 1995 19:50:15 GMT
Raw View
In an article written in the 'C++ Report' in January 1994, pg. 34-38,
Steve Churchill presented an approach to general purpose reference
counting by encapsulating a pointer within simple class template, Ref<T>.

I have implemented his idea, but I have some problems with downcasting
these Ref<T>s from a base class <T> to a class derived from <T>.  Here is
the implementation that I have so far, with an example of what does not work:


// Start of Code.

template <class T> class Ref {
public:
    Ref(T* p = 0)
        {
            p_ = p;
            if ( p_ ) p_->ref();
        }
    Ref(const Ref<T>& r)
        {
            p_ = r.p_;
            if ( p_ ) p_->ref();
        }
    ~Ref()
        {
            if ( p_ )
                p_->unref();
        }

    Ref<T> & operator=( const Ref<T> & r )
        {
            if ( p_ )
                p_->unref( );

            p_ = r.p_;
            if ( p_ )
                p_->ref();
            return *this;
        }

    Ref<T> & operator=( T * r )
        {
            if ( p_ )
                p_->unref( );

            p_ = r;
            if ( p_ )
                p_->ref();
            return *this;
        }

    T* operator->() const
        {
            return p_;
        }

    operator T*() const
        {
            return p_;
        }

    operator SDIRefCounter * ()
        {
            return ( SDIRefCounter *) p_;
        }

protected:
    T* p_;
};



class SDIRefCounter {
public:
    SDIRefCounter() { refCount_ = 0; }
    virtual ~SDIRefCounter() { }

    void ref()
        {
            refCount_++;
        }

    void unref()
        {
            if ( --refCount_ <= 0 )
            {
                delete this;
            }
        }

private:
    unsigned refCount_;

};



class Base : public SDIRefCounter
{
};



class Derived: public Base
{
};




void testIt( )
{
    Ref< Base > baseRef = new Base;

    Ref< Derived > derivedRef = ( Base * ) baseRef;   // Cannot down cast!
                                    // Also tried casting to ( Derived * )
}


// End of Code.


I can get around this in a VERY cheesy way :

   Base * bptr = baseRef;
   derivedRef = ( Derived ) bptr;


My question is : Is there an easier way to downcast these Ref<T>s, preferably
one that is automatic and non-cheesy?

Thanks,
Stew