2016-07-28 9 views
2

I eine Basisklasse haben, die eine virtuelle Funktion hat:reimplementieren eine virtuelle Funktion von der Basisklasse in einer abgeleiteten Klasse Vorlage

class Base { 
    ... 
    virtual void myFunction() { assert(0 && "not implemented yet"); } 

} 

und eine abgeleitete (Templat) -Klasse der Base:

DerviedClass.hpp :

Template<typename T> 
class DerivedClass : public Base, public T { 

    ... 
    void myFunction(); 

} 

DerivedClass.cpp:

template <> 
void DerivedClass<ClassA>::myFunction() { 
//Something ClassA is suppose to do 
} 

Dies wird kompiliert. Aber wenn ich versuche, eine DerivedClass<ClassB> zu instanziieren bekomme ich den Fehler:

IProject.o:-1: erreur : undefined reference to `DerivedClass<ClassB>::myFunction()' 

Warum habe ich diesen Fehler? Warum dauert es nicht Base::myFunction statt mich zu zwingen, eine generische myFunction in DerivedClass oder eine spezialisierte Funktion DerivedClass::myFunction zu implementieren?

Hinweis: die Assertion in myFunction ist, weil ClassB nicht myFunction während runtime anrufen soll. Zum Beispiel wenn myFunction ist getRadius, DerivedClass<Circle>::getRadius() ist in Ordnung, aber DerivedClass<Square>::getRadius() sollte nicht aufgerufen werden.

Anmerkung 2: Die anderen Themen, die ich waren zu diesem Zeitpunkt nicht klar gefunden

+0

Sie möchten wahrscheinlich Ihr Design überdenken, um 'DerivedClass :: getRadius()' zu verbieten. – Jarod42

+1

'DerivedClass :: getRadius()' hätte an erster Stelle nicht existieren sollen. –

+0

Ich habe diesen Entwurf gemacht, um alle DerivedClass als Base zu bearbeiten, ohne 'dynamic_cast' zu brauchen, wenn ich eine Funktion von einer Basisklasse aufrufen will. (Es gibt eine Menge abgeleiteter Klasse mit einer Menge Funktion, die aufgerufen werden muss) – ElevenJune

Antwort

2

Warum es nicht Base::myFunction nimmt statt mich zu zwingen, eine generische myFunction in DerivedClass oder eine spezialisierte Funktion DerivedClass::myFunction zu implementieren?

Sie gezwungen, dass sich durch die Erklärung:

void myFunction(); 

Betrachten voll spezialisiert die Klassenvorlage, die Klassen bedingt mit oder ohne zwingende myFunction generieren, zB:

template <typename T> 
class DerivedClass : public Base, public T { 
    // not overriding  
}; 

template <> 
class DerivedClass<ClassA> : public Base, public ClassA { 
    void myFunction() override; 
}; 

template <> 
void DerivedClass<ClassA>::myFunction() { 
    // something ClassA is supposed to do 
} 

Wenn es einige gemeinsame Sachen gibt, können Sie es einfügen:

template <typename T> 
class DerivedClassCommons : public Base, public T { 
    // common stuff 
}; 

und dann refactor DerivedClass um die einfache Vererbung dieser Klassenvorlage zu verwenden.

Das ist es für Ihre Frage, aber wie andere bemerkten, denke ich, dass Sie ein größeres, Design-Problem haben.

+0

Also, wenn ich das tue, muss ich eine generische Funktion in DerivedClass implementieren? 'Vorlage Inline DerivedClass :: myFunction()'? Es wird niemals Base :: myFunction() für jedes T aufrufen, das ich in 'DerviedClass ' verwende? – ElevenJune

+0

@ElevenJune Hinzugefügt ein Beispiel von dem, worüber ich gesprochen habe. – LogicStuff

+1

Jetzt unterzeichne ich! Vielen Dank ! – ElevenJune

1

Die Funktion ist bereits für alle Typen deklariert. Die Definition könnte von überall her kommen, einschließlich anderer Kompilierungseinheiten. Sie benötigen die Definition nur, wenn die Funktion referenziert wird - und Ihre virtuelle Funktion wird (implizit) während der Konstruktion referenziert.

+0

Ich denke, dass ich deine Antwort verstehe. Wenn ich keinen Verweis auf eine DerivedClass mache, werde ich nie ein Kompilierungsproblem haben, da der Code von DerivedClass nicht erzeugt wird und nie versuchen wird, myFunction zu finden. Aber wenn ich eine DerivedClass irgendwo im Code verwenden muss, gibt es eine Möglichkeit, Aufruf Base :: myFunction() ?? – ElevenJune

+0

@ElevenJune Ihre abgeleitete Klasse dekodiert die Funktion neu, die sie von der Basis erbt. Um dieser Deklaration zu entsprechen, muss daher eine Definition verfügbar sein. Wenn Sie die Version der Basis nicht überschreiben möchten, müssen Sie sie nicht neu deklinieren. Dies ist genau das gleiche wie bei jeder anderen Klasse: Die Tatsache, dass Ihre abgeleitete Klasse hier eine Vorlage ist, ist völlig nebensächlich. –

+0

Ich verstehe jetzt, danke! – ElevenJune

2

Eine andere Methode, um die Compiler-Fehler (nicht die Design Fehler) zu beheben, ist die Definition von myFunction der abgeleiteten Vorlage zu bewegen:

class Base { 
    virtual void myFunction() = 0; 
} 

template<typename T> 
class DerivedClass : public Base, public T { 
    void myFunction() { 
     throw "not implemented, go away"; 
    } 
} 

und dann spezialisieren nur die Methoden, die Sie brauchen:

template <> 
void DerivedClass<ClassA>::myFunction() { 
//Something ClassA is suppose to do 
}