Template Switch um abgeleitete Klasse zu erstellen



  • Naja, ich dachte jemand hätte da nen ganz anderen goldenen weg.

    Ich versuche es also so:

    case 2:
       Klasse3<double>* a = NULL;
       Get(a);
    
    template <> void
    Switch_Algorithm<double>::Get(Basis_Klasse<double> * a)
    {
    	a = new Klasse3<double>();
    }
    
    // z.B int typ
    template <> void
    Switch_Algorithm<int>::Get(Basis_Klasse<int>* a)
    {
    }
    

    die fehlermeldung lautet:

    Switch_Algorithm.cpp:35: Fehler: expected initializer before »<« token
    Switch_Algorithm.cpp:41: Fehler: expected initializer before »<« token
    

    Danke



  • Mal abgesehen davon, dass das mit dem Pointer-Argument so nicht klappen kann (wenn schon, dann "Basis_Klasse<double> *&"), sieht mir das eher nach einem Problem Deiner Deklarationsreihenfolge aus: Vermutlich kennt der Compiler an der Stelle, an der er Klasse3 braucht, diese noch nicht.

    Für welche Codezeile meldet er denn den Fehler ? (Bitte jetzt nicht "Zeile 35" antworten, soviel Zeilen hat nämlich Dein Beispiel gar nicht 😉 ).

    Verkürze Deinen Sourcecode doch einfach mal so, dass der Fehler noch produziert wird, aber NICHTs drinsteht, was nicht zur Sache gehört.

    Gruß,

    Simon2.



  • Danke für die Geduld.

    Leider ist das verkürzen des quellcodes nicht so ohne weiteres möglich. Also ich nehme an du möchtest ein lauffähiges programm oder?

    Der Fehler kommt in diesen Zeilen:

    Switch_Algorithm<double>::Get(Basis_Klasse<double>*& a)
    
    Switch_Algorithm<int>::Get(Basis_Klasse<int>*& a)
    

    Vermutlich kennt der Compiler an der Stelle, an der er Klasse3 braucht, diese noch nicht.

    Doch die kennt er. Denn wenn ich es für allgemeine Typen schreibe funktioniert alles:

    template <class T>	Basis_Klasse<T>*
    Switch_Algorithm<T>::Get_Algorithm(const int level)
    {
    	switch(level)
    	{
    		case 0:
    			return new Klasse1<T>();
    		case 1:
    			return new Klasse2<T>();
    		case 2:
                            return new Klasse3<T>();
    		// no default case
    	}
    	return NULL;
    }
    

    Was ich machen möchte ist: Klasse 3 ist eine template basierte Klasse die ja von der template-basierte Basis-Klasse erbt. Allerdings soll für den case 2: nur der typ double "gemacht" werden.

    Da ja Klasse3 von der Basisklasse erbt, muss doch Klasse3 auch template-basiert sein oder?

    Vielleicht gibt es auch einen anderen Weg als so wie oben?

    Also ich versuche nochmal den code so zu reduzieren dass ihr mich vielleicht besser versteht:

    IN DER MAIN.

    Switch_Algorithm<double> o_alg;
    Basis_Klasse<double>* alg_ptr  = o_alg.Get_Algorithm(level);
    
    // oder auch so z.B:
    Switch_Algorithm<int> o_alg;
    Basis_Klasse<int>* alg_ptr  = o_alg.Get_Algorithm(level);
    

    SWITCH

    template <class T>
    class Switch_Algorithm
    {
    	public:
    
    		Basis_Klasse<T>* Get_Algorithm(const int level);
    
    		void Get(Basis_Klasse<double>*& a);
    		void Get(Basis_Klasse<int>*& a);
    };
    
    template <class T>	Basis_Klasse<T>*
    Switch_Algorithm<T>::Get_Algorithm(const int level)
    {
    	switch(level)
    	{
    		case 0:
    			return new Klasse1<T>();
    		case 1:
    			return new Klasse2<T>();
    		case 2:
    
    			Basis_Klasse<T>* a = NULL;
    			Get(a); 
    			return a;
    	}
    }
    
    template <> void
    Switch_Algorithm<double>::Get(Basis_Klasse<double>*& a)
    {
    	a = new Klasse3<double>();
    }
    
    template <> void
    Switch_Algorithm<int>::Get(Basis_Klasse<int>*& a)
    {
    	a = NULL;
    }
    

    DIE BASISKLASSE:

    template <class T>
    class Basis_Klasse
    {
    
    	public:
    
    		// Destructor
    		virtual 	~Basis_Klasse<T>(){ }
    };
    

    UND EINMAL DIE KLASSE3 - sie ist wie auch Klasse 2 und klasse 1 gleich:

    template <class T>
    class Klasse2 : public Basis_Klasse<T>
    {
    	public:
    };
    


  • afaiko schrieb:

    ....
    Der Fehler kommt in diesen Zeilen:

    Switch_Algorithm<double>::Get(Basis_Klasse<double>*& a)
    
    Switch_Algorithm<int>::Get(Basis_Klasse<int>*& a)
    

    ...

    Was für mich danach aussieht, als würde er da Basis_Klasse nicht kennen... (war die andere Möglichkeit - hatte eine 50/50-Chance verbockt 😉 ).

    Hast Du auch schon alle templates im Header implementiert ?

    Bei mir compiliert jedenfalls Folgendes problemlos (abgesehen von einer "unused variable"-Warning bzgl. alg_ptr) :

    // header.h
    template <typename T>
    struct Basis_Klasse {
       virtual ~Basis_Klasse(){ }
    };    
    
    template <typename T>
    struct Klasse1 : public Basis_Klasse<T> {
       virtual void f() {}
    };    
    
    template <typename T>
    struct Klasse2 : public Basis_Klasse<T> {
       virtual void g() {}
    };    
    
    template <typename T>
    struct Klasse3 : public Basis_Klasse<T> {
       virtual void h() {}
    };    
    
    template <typename T>
    struct Switch_Algorithm {
            Basis_Klasse<T>* Get_Algorithm(const int level);
            void Get(Basis_Klasse<T>*& a);
    };    
    
    template <typename T>
    Basis_Klasse<T>*  Switch_Algorithm<T>::Get_Algorithm(const int level){
       Basis_Klasse<T>* a = 0;
        switch(level) {
            case 0: a = new Klasse1<T>(); break;
            case 1: a = new Klasse2<T>(); break;
            case 2: Get(a); break;
        }
        return a;
    }
    
    // main.cpp
    #include "header.h"
    
    template <>
    void Switch_Algorithm<int>::Get(Basis_Klasse<int>*& a) {
        a = 0;
    }  
    template <>
    void Switch_Algorithm<double>::Get(Basis_Klasse<double>*& a) {
        a = new Klasse3<double>();
    }
    
    int main (int argc, char **argv) {
       Switch_Algorithm<int> o_alg;
       Basis_Klasse<int>* alg_ptr  = o_alg.Get_Algorithm(2);
       return 0;
    }
    

    ... was nicht bedeutet, dass ich das Design gutheiße - ich finde allein schon diese "implizite Typdefinition mittels level" bedenklich.

    Gruß,

    Simon2.



  • Hallo Simon,

    ja alles templates sind im Header implementiert. Wie gesagt - wenn ich es als Templatebasierten Parameter T setze geht ja alles.

    Wie wird denn das üblicherweise gemacht wenn man nur eine spezialisierung haben wollen würde?

    Gruß



  • Hmm....zum design.

    Wie mache ich es denn sonst wenn ich abhängig von einem parameter unterschiedliche Abgeleitete Klassen haben möchte?
    Ich bin für andere Vorschläge immer gern zu haben!



  • Also als Erstes mal sollte man IMHO diese "Pointerrückgabe" möglichst vermeiden.
    Bei einem zurückgegebene Pointer ist nicht klar, wem das dahinterligende Objekt gehört (sprich: wer ihn löscht). Dazu müsste der Nutzer von Switch_Algorithm den Source kennen und bei der nächsten Version kann das alles schon wieder anders sein.
    Dem könnte man entweder durch boost::smart_pointer beikommen oder gleich die Ressource kapseln (irgendwer will ja etwas mit dem Objekt machen: Dann soll dem das auch gehören und er aufräumen).

    Ich schau mal, ob ich ein Beispiel bastele...

    Gruß,

    Simon2.



  • Danke Simon - das wäre Klasse wenn Du mir ein beispiel schreiben könntest.
    Wenns geht ohne Boost...



  • So ne ähnliche Frage gab's kürzlich schon mal, vielleicht findest du in dem alten Thread irgendeine Anregung: http://c-plusplus.net/forum/viewtopic-var-t-is-194257.html 😃



  • Tatsache - da gehts ja richtig rund ...
    also so wie ich das aus dem Thread herauslesen kann wird das also doch so in der Art gemacht mit dieser Unterscheidung? Zumindest fällt mir so nichts anderes ein. Und um jetzt zu meinem Problem zurückzukommen: Wie sollte man dann eine Template-Spezialisierung in so einem Template-basierten switch einbauen?



  • In deinem Beispiel muss die zurückgegebene Basis_Klasse mit dem selben Typ parametrisiert werden, wie die Switch_Algorithm-Klasse, da sie die gleiche Typvariable haben:

    template <class T>    
    Basis_Klasse<T>*
    Switch_Algorithm<T>::Get_Algorithm(const int level) { ... }
    

    Wenn du Basis_Klasse mit einem anderen Typ parametrisieren willst, musst du eine andere Typvariable verwenden, zB. mit einer Template-Memberfunktion:

    template <class T>
    template <class R>
    Basis_Klasse<R>*
    Switch_Algorithm<T>::Get_Algorithm(const int level) {
        switch (level) {
        case 0: return new Klasse1<T>;
        case 1: return new Klasse2<T>;
        case 2: return new Klasse3<double>;
        }
    }
    

    Dann musst du R aber beim Aufruf mit angeben:

    Basis_Klasse<int>* pMyObj->Get_Algorithm<int>(mylevel);
    

    Nicht nur, dass das unschön ist, R und level hängen voneinander ab. Besser ist es, wenn deine Basis_Klasse keine Template-Klasse ist.


Anmelden zum Antworten