鉴于下面的代码,编译器显示一条指向error: templates may not be ‘virtual’
的消息。有没有人建议如何解决这个问题?
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 ){
...
}
答案 0 :(得分:17)
最容易理解为什么这是非法的原因是考虑vtable。当然,这只是一个常见的实现,其他的是允许的。但是C ++中的所有virtual
函数都被设计为可以使用vtable实现它们。
现在,vtable
的{{1}}中有多少条目? CFoo<int>
有条目吗? doSomething<float>
? doSomething<float*>
?这些模板允许生成无限的函数集。通常这没问题,因为你只使用有限的子集,但对于虚函数,这个子集是未知的,因此vtable需要是无限的。
现在,您可能真的只想在vtable中输入一个条目。在这种情况下,您可以按如下方式编写:
doSomething<float**>
这意味着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;
};
的vtable将有一个CFoo<int, float>
条目。
答案 1 :(得分:2)
您可以使用我们在Symbian中称为“模板设计模式”的内容。以下示例代码为您提供了一个想法:
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;
};
答案 2 :(得分:1)
嗯,错误信息很清楚。 Member function templates can't be virtual。如何解决这个问题取决于您的问题,但最简单的方法是使成员函数非虚拟并重新考虑您的设计。
答案 3 :(得分:1)
如果您确实需要将此方法设为虚拟,请考虑使CBar<>
多态并传递一个未模板化的基类型。
// non-templated base class
class BarBase
{
// common methods go here..
};
template <typename BAR_TYPE>
class CBar : public BarBase
{
// implement methods from BarBase ...
};
template < class FOO_TYPE>
class CFoo{
public:
...
// now we take the base type, and this method does not need to be a template
virtual void doSomething( BarBase const* ptrBar );
...
virtual ~CFoo();
protected:
MyClass < FOO_TYPE > * m_pClass;
};
template < class FOO_TYPE >
void CFoo<FOO_TYPE>::doSomething( BarBase const* ptrBar ){
..
}