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