2011-02-10 25 views
11

Dato il codice sotto, il compilatore mostra un messaggio che indica che error: templates may not be ‘virtual’. Qualcuno ha un suggerimento su come risolvere il bug?non possono essere 'virtuali'

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

non è un bug, è una funzionalità, non è possibile dichiarare un modello di funzione che è virtuale. Devi esplorare un altro approccio, e questo dipende da cosa stai cercando di fare ... – Nim

+0

il fatto è che il parametro della funzione è un oggetto modello e non posso cambiare la sua dichiarazione. – Javier

+0

perché hai bisogno di una funzione diversa per ogni istanza di CBar? –

risposta

16

Il motivo più semplice per capire perché questo è illegale è considerando il vtable. Certo, questa è solo un'implementazione comune, e altri sono consentiti. Ma tutte le funzioni virtual in C++ sono progettate in modo tale che possano essere implementate con un vtable.

Ora, quante voci ci sono nello vtable di CFoo<int>? C'è una voce per doSomething<float>? E doSomething<float*>? E doSomething<float**>? Modelli come questi consentono di generare un insieme infinito di funzioni. Di solito non è un problema, poiché si usa solo un sottoinsieme finito, ma per le funzioni virtuali questo sottoinsieme non è noto, e quindi il vtable dovrebbe essere infinito.

Ora, è possibile che tu volessi davvero solo una singola voce nel vtable. In tal caso, ci si scrive come segue:

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

Ciò significa che il vtable per CFoo<int, float> avrà una voce, per doSomething(float const&).

+1

Potrebbe essere noto nella fase di collegamento dopo che tutte le unità di compilazione sono state compilate. Lo standard è un po 'veloce su scarto qui. –

+3

@ v.oddou: non realisticamente. Il linker dovrebbe abbinare tutte le chiamate virtuali a tutte le possibili classi base e creare istanze di modelli. Queste istanze devono quindi essere compilate. Quelle nuove istanze a loro volta possono contenere nuove chiamate virtuali, quindi questo processo dovrebbe essere iterativo. – MSalters

1

Bene, il messaggio di errore è abbastanza chiaro. Member function templates can't be virtual. Come risolvere questo dipende dal tuo problema, ma la cosa più semplice da fare sarebbe rendere le funzioni membro non virtuali e riconsiderare il tuo design.

+0

grazie. Nel mio caso, ho bisogno di avere questo "refBar" come parametro e appartiene a una classe basata su modelli. – Javier

+1

Sapete quanti parametri modello diversi ci saranno? 3? 8? Puoi sovraccaricare la funzione per ognuno di questi? Se non lo sai, in che modo il compilatore saprà quante funzioni virtuali ci sono? –

+0

@Bo: solo 2 parametri: FOO_TYPE e BAR_TYPE – Javier

1

Se è davvero necessario rendere questo metodo virtuale, prendere in considerazione la realizzazione di CBar<> polimorfico e passare un tipo di base in cui non è presente un modello.

EDIT: qualcosa di simile:

// 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

scusate, non l'ho capito. ti dispiace fare un esempio? – Javier

1

È possibile utilizzare ciò che noi chiamiamo in Symbian come "design pattern modello". Ecco un esempio di codice per darti un'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; 
}; 
+15

La formattazione mi fa venir voglia di ferire qualcosa. – GManNickG

+0

Mi dispiace, l'ho formattato ora. – Viren

+0

grazie per l'illustrazione del codice. Ho definito il metodo 'doSomething' come' template' a causa del suo argomento. Ci sono solo due tipi di template, quello corrispondente a 'CFoo' e l'altro a 'CBar'. Penso che dichiarando 'CFoo ' come una doppia classe template dovrebbe essere OK. Cosa ne pensi? – Javier

Problemi correlati