Basisklasse als Templateparameter übergeben (sinnvoll???)



  • Ja, das ist völlig in Ordnung und auch gut. Nennt sich policy-basierters Klassendesign. 😉



  • Ok, danke.

    Und kannst du was mit dem Linker-Error anfangen?

    "undefined reference to" und dann folgt der Konstruktor meiner Klasse, also z.B.
    Klasse<Kaempfer>::Klasse()

    Aber halt nur manchmal.

    Deswegen steige ich da auch nicht durch...

    Edit:
    Ich füge nochmal den Code an.
    Aber an dem kann's ja eigentlich nicht liegen, wenn's mal geht und mal nicht...

    // klasse.h
    #include <iostream>
    #include <string>
    #include "char.h"
    #include "kaempfer.h"
    
    #ifndef _KLASSE_H_
    #define _KLASSE_H_
    
    template <class T>
    class Klasse : public T, public Char
    {
          public:
          Klasse();
    };
    #endif
    
    // klasse.cpp
    #include <iostream>
    #include "klasse.h"
    #include "char.h"
    
    template <class T>
    Klasse<T>::Klasse():Kaempfer()
                   {
                       name = "Sinthoras";
                       iTW = 1;
    };
    
    // main.cpp
    (...)
    Klasse<Kaempfer> NSC;
    (...)
    

    Manchmal klappt es halt...
    Eben auch als ich die Zeile "Klasse<Kaempfer> NSC;" auskommentiert habe (es scheint also wirklich am Konstruktor zu liegen) und seltsamerweise auch, als ich "klasse.cpp" (mit dem Konstruktor) als Test per #include in main eingebunden habe. Soll man ja nich machen.

    Edit2: Also irgendwie habe ich das Gefühl, er peilt nicht, dass die Konstruktor zu Klasse nicht in klasse.h sondern in klasse.cpp ist.
    Aber die Dateien sind hübsch alle in einem Projekt und manchmal gehts ja irgendwie...



  • Bei templates müssen Funktionsprototyp und Implementation in der selben Einheit sein.

    // klasse.h
    #include <iostream>
    #include <string>
    #include "char.h"
    #include "kaempfer.h"
    
    #ifndef _KLASSE_H_
    #define _KLASSE_H_
    //
    template <class T>
    class Klasse : public T, public Char
    {
          public:
          Klasse();
    };
    
    #include "klasse.cpp"  //hier so
    #endif
    
    // klasse.cpp
    #include <iostream>
    //#include "klasse.h" und das weg
    #include "char.h"
    
    template <class T>
    Klasse<T>::Klasse():Kaempfer()
                   {
                       name = "Sinthoras";
                       iTW = 1;
    };
    

    oder gleich alles in den header



  • Ok, danke, vielen Dank, euch allen.

    Edit:
    Hm, wenn ich es so einbinde, bekomme ich dann folgende Meldungen:

    expected constructor, destructor, or type conversion before '<' token
    expected `;' before '<' token

    beides bezogen auf die Zeile:

    Klasse<T>::Klasse():Kaempfer()

    Wenn ich es direkt im Header mache, kommt wieder "undefinde reference to..".



  • struct A
    {
    };
    
    struct Char
    {
        std::string name;
        int iTW;
    };
    
    template <class T>
    class Klasse : public T, public Char
    {
    public:
        Klasse();
    };
    
    template <class T>
    Klasse<T>::Klasse()
    {
        name = "Sinthoras";
        iTW = 1;
    };
    

    Schluckt mein Compiler :o



  • Z.Z. übersetzt er beide Versionen (also auch die falsche), wenn er lustig ist.

    Wenn gerade lieber abstürzt, macht er auch das... 😡

    😕



  • So mir war grad langweilig, hab dir hier nen Vorschlag. Schau mal ob er dir gefällt.

    // Getestet, Pseudofunktionen als Bildschirmausgabe als Kontrolle obs geht
    #include <iostream>
    
    using namespace std;
    
    // Charakter Typen
    class Magier{
    public:
        static void angreifen(){
            cout << "zaubere();" << endl;
        }
    };
    
    class Kaempfer{
    public:
        static void angreifen(){
            cout << "kaempfe();" << endl;
        }
    };
    
    class Schurke{
    public:
        static void angreifen(){
            cout << "tu_schurkiges();" << endl;  // naja Namen sind so ne Sache ;)
        }
    };
    
    // Volktypen
    class Mensch{
    public:
        static void rede( const std::string& text ){
            cout << "sprich_menschisch( text );" << endl;
        }
    };
    
    class Zwerg{
    public:
        static void rede( const std::string& text ){
            cout << "sprich_zwergisch( text );" << endl;
        }
    };
    
    class Ork{
    public:
        static void rede( const std::string& text ){
            cout << "sprich_orkisch( text );" << endl;
        }
    };
    
    // Spielfigur-Template
    template< typename CharakterT, typename VolkT >
    class Spieler{
    public:
        void handle(){
            VolkT::rede( "Halt, oder ich schiesse!" );
            CharakterT::angreifen();
        }
    };
    
    int main()
    {
    // Jede Kombination möglich
        Spieler< Schurke, Zwerg > spieler1;
        Spieler< Kaempfer, Ork > spieler2;
        Spieler< Kaempfer, Mensch > spieler3;
    // Alle gleich zu bedienen aber verschiedenes Verhalten
        spieler1.handle();
        spieler2.handle();
        spieler3.handle();
    }
    

    Du kannst nun jeden Spieler individuell erstellen, und auch jederzeit neue Charaktere oder Völker hinzufügen.
    Nennt sich, wie schon gesagt, policy-based design und ist sehr flexibel.



  • Ja, danke, so hatte ich mir das vorgestellt 🙂

    Sinthoras:

    template<class Klasse, class Volk> 
    class NSC : public Klasse, public Volk 
    {... blabla alles hübsch kombinieren...};
    

    Entspricht ja auch ungeähr dem, was mich damit meinte.

    Eine Frage aber noch:

    Wenn ich das hier

    template< typename CharakterT, typename VolkT >
    class Spieler{
    public:
        void handle(){
            VolkT::rede( "Halt, oder ich schiesse!" );
            CharakterT::angreifen();
        }
    };
    

    so (oder so änhlich) mache

    template< typename CharakterT, typename VolkT >
    class Spieler : public CharakterT, public VolkT {
    public:
        (...)
    };
    

    Kann ich die Funktionen doch direkt aufrufen oder?
    Also in main() z.B.
    Spieler<Krieger, Zwerg> Gimli;
    Gimli.angreifen();

    Oder nicht?

    Danke jedenfall für Deine Mühe.



  • Hmm brauchst nicht unbedingt erben.
    Kannst auch einfach weiterleiten:

    template< typename CharakterT, typename VolkT >
    class Spieler{
    public:
        void angreifen(){
            CharakterT::angreifen();
        }
    };
    
    //...
    Gimli.angreifen();
    //...
    

    Der Vorteil davon ist, dass du keine vtable für die virtuellen Funktionen brauchst. Die Weiterleitung wird garantiert jeder einigermassen schlaue Kompiler wegoptimieren.



  • Aber ganz ohne Vererbug werde ich wohl nicht auskommen, denn ich möchte ja, dass der Magier Zauber bekommt, unser Freund Gimli hier aber nicht.

    Wenn ich dann einfach in der Klasse Magier entsprechende Funktionen einbaue, in der Klasse Krieger aber nicht, hat sie am Ende eben auch nur der, der vom Magier erbt.

    Also so hatte ich mir das jedenfalls gedacht...



  • Sinthoras schrieb:

    Aber ganz ohne Vererbug werde ich wohl nicht auskommen, denn ich möchte ja, dass der Magier Zauber bekommt, unser Freund Gimli hier aber nicht.

    Wenn ich dann einfach in der Klasse Magier entsprechende Funktionen einbaue, in der Klasse Krieger aber nicht, hat sie am Ende eben auch nur der, der vom Magier erbt.

    Also so hatte ich mir das jedenfalls gedacht...

    Ok da ist was dran.


Anmelden zum Antworten