模板可能不是'虚拟'

时间:2011-02-10 19:52:57

标签: c++ templates polymorphism virtual

鉴于下面的代码,编译器显示一条指向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 ){
    ...
}

4 个答案:

答案 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 ){
..
}