The first question you have to ask yourself is...
Which operations are semantically equivalent on every object of each class of the family
B<T>
? If an operation is common to all
B<T>
then you can stick it in an interface and implement it in each derived class, if it's not you shouldn't be even trying. Anything defined in
A
has to be independent of anything defined in
B<T>
- including its template parameter.
Setters are never semantically equivalent, unless you want to be able to do something like:
void do_something( A *a, int i, float f )
{
a->SetValue( i );
a->SetValue( f );
}
which as far as I can tell from your comment you don't want. However things like
A::print( std::ostream & )
can be in
A
's its definition doesn't rely on anything in
B<T>
.
Now, if you want to do something like your original "problem" you can use a really nasty hack:
class A
{
public:
virtual void do_something_with_a_T( void * ) = 0;
};
template< typename T >
class B
{
public:
virtual void do_something_with_a_T( void *p )
{
T *t = static_cast< P * >( p );
t;
}
};
class P
{
};
class Q
{
};
int main()
{
P p;
Q q;
B<p> b1;
A *a = &b1;
a->do_something_with_a_T( &p );
B<p> b2;
a = &b2;
a->do_something_with_a_T( &q );
}
the pressence of the
static_cast
and
void *
should tell you this isn't typesafe and never will be.
You can be more typesafe using the solution you came up with or an equivalent:
class C
{
};
template< typename T >
class D : public C
{
public:
virtual void do_something_with_a_T( T * )
{
}
};
template< typename T >
void do_something_with_a_T( C *c, T *t )
{
if( D<t> *p = dynamic_cast< D<t> >( c ) )
{
p->do_something_with( *t );
}
}
int main()
{
P p;
Q q;
D<p> d1;
C *c = &d1;
do_something_with_a_T( c, &p );
D<p> d2;
c = &d2;
do_something_with_a_T( c, &q );
}
which has the advantage of not needing an additional class and is typesafe, if completely pointless.
So, TLDR:
- your initial design was wrong as
B<T>::SetValue
wasn't semantically equivalent for all
T
- there are at least two nasty hacks, one of which you discovered