2011-02-10 3 views
11

Учитывая приведенный ниже код, компилятор показывает сообщение, указывающее, что 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){ 
    ... 
} 
+5

Это не ошибка, это функция, вы не можете объявить шаблон функции, который является виртуальным. Вам нужно изучить другой подход, и это зависит от того, что вы пытаетесь сделать ... – Nim

+0

Дело в том, что параметр функции является объектом шаблона, и я не могу изменить его объявление. – Javier

+0

Почему вам нужна другая функция для каждого экземпляра CBar? –

ответ

16

Простейшая причина, почему это незаконно, - это рассмотреть таблицу vtable. Конечно, это всего лишь одна общая реализация, и другие разрешены. Но все функции virtual в C++ разработаны таким образом, что они могут быть реализованы с помощью vtable.

Теперь, сколько записей в vtable от CFoo<int>? Есть ли запись для doSomething<float>? И doSomething<float*>? И doSomething<float**>? Такие шаблоны позволяют создавать бесконечный набор функций. Обычно это не проблема, поскольку вы используете только конечное подмножество, но для виртуальных функций это подмножество неизвестно, и поэтому vtable должен быть бесконечным.

Теперь, возможно, вам действительно нужна только одна запись в таблице vtable. В этом случае, вы бы написать это следующим образом:

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; 
}; 

Это означает, что для CFoo<int, float> виртуальные таблицы будут иметь одну запись, для doSomething(float const&).

+1

Он может быть известен на этапе ссылки после того, как все компиляционные единицы были скомпилированы. Этот стандарт немного ускользнут здесь. –

+3

@ v.oddou: Не реалистично. Компонент должен будет сопоставлять все виртуальные вызовы со всеми возможными базовыми классами и создавать шаблоны. Затем эти экземпляры необходимо скомпилировать. Эти новые экземпляры, в свою очередь, могут содержать новые виртуальные вызовы, поэтому этот процесс должен быть итеративным. – MSalters

1

Ну, сообщение об ошибке довольно ясно. Member function templates can't be virtual. Как решить это, зависит от вашей проблемы, но проще всего было бы сделать функции членов не виртуальными и пересмотреть ваш дизайн.

+0

спасибо. В моем случае мне нужно, чтобы этот параметр «refBar» был параметром, и он принадлежит шаблону. – Javier

+1

Знаете ли вы, сколько будет разных параметров шаблона? 3? 8? Можете ли вы перегрузить функцию для каждого из них? Если вы не знаете, как компилятор знает, сколько виртуальных функций есть? –

+0

@Bo: только 2 параметра: FOO_TYPE и BAR_TYPE – Javier

1

Если вам действительно нужно сделать этот метод виртуальным, подумайте о том, чтобы сделать CBar<> полиморфным и передать базовый тип, в котором нет шаблонов.

EDIT: что-то вроде этого:

// 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){ 
.. 
} 
+0

Извините, я этого не понял. вы не возражаете, чтобы сделать пример? – Javier

1

Вы можете использовать то, что мы называем в 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; 
}; 
+15

Форматирование заставляет меня хотеть что-то повредить. – GManNickG

+0

Извините, я отформатировал его сейчас. – Viren

+0

спасибо за код иллюстрации. Я определил метод 'doSomething' как' template' из-за его аргумента. Существует только два типа шаблонов, один из которых соответствует «CFoo», а другой - «CBar». Я думаю, что, объявив 'CFoo ' как двойной шаблонный класс, должно быть ОК. Как вы думаете? – Javier

Смежные вопросы