Click here to Skip to main content
15,890,717 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
Hi,

I would like to bypass the fact that template member functions can't be virtual. Here is my code:

C++
class A
{
   // abstract class
}

template <class T> class B : public class A
{
   void SetValue(const T p_Value&);
   T m_Value;
}

template <class T> void CVariable<T>::SetValue(const T& p_Value) 
{ 
   m_Value = p_Value ;
}


As I need so store the template objects (of type B<int>, B<MyClass>...) in a list , I have an abstract class A to generalize them.

The problem is that I would like to do a SetValue() from the base class A which isn't possible as template member functions can't be virtual.

The only solution I found is to use an abstract type so that SetValue() is no more a template method:

C++
template <class T>
class DataType : public DataTypeInterface
{
} 

class A
{
   // abstract class
   virtual void SetValue(const DataTypeInterface p_Value&) = 0;
}

template <class T> class B : public class A
{
   void SetValue(const DataTypeInterface p_Value&);
   DataType<T> p_Value;
}

template <class T> void CVariable<t>::SetValue(const DataTypeInterface & p_Value) 
{ 
   // Here do a dynamic_cast to check type T
   m_Value = p_Value ;
}

However, I don't want to do dynamic casts. Is there any solution?
Thanks a lot.

Carole
Posted
Updated 26-Jun-12 4:15am
v2

To put simply - No. You cannot combine virtual methods and templates in C++ within a single derivation. You need to make a choice between the two, based on business requirements of your project.

But from what I pick up, you need to make calls through the base type, which then requires use of virtual methods, which makes your choice easier ;)

You can only enhance your derived classes with template-type properties, but that's as far as virtual and template can dance with each other in C++ ;)
 
Share this answer
 
v5
// The problem is that I would like to do a SetValue() from the base class A
C++
class A
{
public:
  virtual bool CanAcceptValue(const COleVariant& cVal) const = 0;
  virtual bool TrySetValue(const COleVariant& cVal) = 0;
};

Yes, it would be a designe problem :) :
C++
void testYourList(CYourVarList& list)
{
  bool bResult(true);
  
  POSITION pos(list.GetHeadPosition());
  while (pos) {
    COleVariant cVal(3);
    A* pcVar(list.GetNext(pos));
    // generalized call, but maybe without result :) :
    bResult = pcVar->TrySetValue(cVal) && bResult; 
  }

  ASSERT(bResult); // not all vars could be set :)
}

In other words: even in the "generalized" form of A::SetValue(..)
you will need info about the type of an A-object to have the success of the setting.

That's why I would generalize only the unspecific functions:
C++
class A
{
public:
  virtual void GetValueAsXMLString(CString& cszValue) const = 0;
};

...and let the template functions be strange by their parameters :)
 
Share this answer
 
Comments
Vitaly Tomilov 26-Jun-12 20:40pm    
Couldn't understand what you are talking about. Probably it's just the English.
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:
C++
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:
C++
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 );
            // do something with *t here...
            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:
C++
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
 
Share this answer
 
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900