Given the code below, the compiler is showing a message pointing that error: templates may not be ‘virtual’
. Does anyone have a suggestion on how to solve the bug?
template < class FOO_TYPE>
class CFoo{
public:
...
template < class BAR_TYPE >
virtual void doSomething( const CBar<BAR_TYPE> &); // here's the error
...
virtual ~CFoo();
protected:
MyClass < FOO_TYPE > * m_pClass;
};
template < class FOO_TYPE >
template < class BAR_TYPE >
void CFoo<FOO_TYPE>::doSomething( const CBar<BAR_TYPE> & refBar ){
...
}
The easiest reason to see why this is illegal is by considering the vtable. Sure, that's just one common implementation, and others are allowed. But all virtual
functions in C++ are designed such that they can be implemented with a vtable.
Now, how many entries are there in the vtable
of CFoo<int>
? Is there an entry for doSomething<float>
? And doSomething<float*>
? And doSomething<float**>
? Templates such as these allow an infinite set of functions to be generated. Usually that's no problem, as you use only a finite subset, but for virtual functions this subset isn't known, and therefore the vtable would need to be infinite.
Now, it's possible that you really wanted only a single entry in the vtable. In that case, you'd write it as follows:
template < class FOO_TYPE, class BAR_TYPE>
class CFoo{
public:
...
virtual void doSomething( const CBar<BAR_TYPE> &); // now OK.
...
virtual ~CFoo();
protected:
MyClass < FOO_TYPE > * m_pClass;
};
This means that the vtable for CFoo<int, float>
will have one entry, for doSomething(float const&)
.
You can use what we call in Symbian as "template design pattern". Here is sample code to give you an idea:
class Base {
public:
virtual int DoSomething() = 0;
protected:
Base();
};
class IntermediateBase : public Base {
protected:
IntermediateBase(void* aSomeParam, void* aArg)
: iSomeParam(aSomeParam)
, iArgs(aArg)
{}
virtual int DoSomething() = 0;
protected:
void* iSomeParam;
void* iArgs;
};
template <class TYPE, class INPUT>
class ConcreteClass : public IntermediateBase {
typedef int (TYPE::*MemberFuncPtr)(const INPUT&);
public:
ConcreteClass(TYPE& aCommandType,
INPUT& aArgumentsToCommand,
MemberFuncPtr aMFP)
: IntermediateBase(static_cast<TYPE*>(&aCommandType),
static_cast<INPUT*>(&aArgumentsToCommand) )
, iMFP(aMFP)
{}
virtual int DoSomething() // VIRTUAL AND INLINE Note - dont make it
// virtual and inline in production if
// possible to avoid out-of-line copy
{
return static_cast<TYPE*>(iSomeParam)->*ConcreteClass::iMFP)
(*(static_cast<INPUT*>(iArgs));
}
private:
MemberFuncPtr iMFP;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With