Templates und OOP



  • Achja ich hab mich noch gar nicht über meine Umgebung geäusert 😉

    Linux KUbuntu
    gcc

    Als IDE werde ich KDevelop ein. Leider bin ich nicht so ganz mit der automatischen Codegeneration bzw. des Popups-Menü zufrieden. Da wurde ich von Java mit Netbeans gerade zu verwöhnt 😉 Das ist wohl in C++ etwas ... 😃

    Die Fragen aus meinen letzten Post sind nach wie vor offen 😉



  • template<Foo T>
    das ist nicht was du denkst.
    Du übergibst hier keinen Typ.
    Typübergabe geht nur mit class oder typename.



  • Was soll eigentlich der Sinn dahinter sein ein template zu machen und es dann auf GENAU einen Typen festzunageln?



  • void* schrieb:

    Was soll eigentlich der Sinn dahinter sein ein template zu machen und es dann auf GENAU einen Typen festzunageln?

    Einen Type und alle Kindklassen von diesem Typ.
    Der Sinn? Typensicheres programmieren. Bei der Kindklasse sollte sich der Typ T automatisch nach FooChild wandeln -> erstelle ich eine Instanz der FooChild Klasse so gibt mir FooChild->getVariRef() automatisch FooChild zurück. Vielleicht nicht das beste Beispiel 😃 In Java und C# ohne Probleme möglich in C++ komme ich nicht drauf.

    Kennt das hier keiner? 😞



  • Ich verstehe immer noch nicht warum du keine Polymorphie verwendest, wenn dir das so wichtig ist.

    Und Typsicher ist es sowieso.



  • Ich schreibe hier mal ein Java - Beispiel. Hoffentlich könnt ihr das lesen 😉 und mir ein paar Tipps für eine C++ Umsetzung geben 😉

    interface Knoten<T> {
    T getParent();
    T getChild();
    }
    
    class TreeElement<E extends TreeElement, T> implements Knoten<T> {
    // Irgendwelche Hilfsmethoden
    public E getElement() { return this; }
    }
    
    class Blatt<T> extends TreeElement<Blatt, T> {
    //
    }
    
    class Zweig<T> extends TreeElement<Zweig, T> {
    //
    }
    

    So, in den Klassen Blatt und Zweig werden nun alle mit E Deklarierten Typen der TreeElement - Klasse an Blatt bzw. Zweig angepasst. TreeElement ist keine abstrakte Klasse und es kann somit auch eine Instanz hier von erstellt werden. Hier wäre der Rückgabewert E vom Typ TreeElement.



  • Du gehst das falsch an. Du darfst einer Sprache keinen anderen Stil aufzwingen. Löse es besser mit C++ Mitteln und Vorgehensweisen. Sonst kannst du ja Java nehmen. 😉



  • drakon schrieb:

    Du gehst das falsch an. Du darfst einer Sprache keinen anderen Stil aufzwingen. Löse es besser mit C++ Mitteln und Vorgehensweisen. Sonst kannst du ja Java nehmen. 😉

    Ich habe nicht vor C++ irgend etwas auf zu zwingen 😉 Wie löse ich das in C++? Ich dachte immer das C++ objektorientierte Programmierung unterstützt, aber ausser Klassen und Vererbung hab ich da kein weiteres Konzept aus OOP gefunden.

    Also, wie löse ich das in C++?



  • jetzt musst du dich aber entscheiden.
    Entweder du benutzt generische Programmierung und damit Templates.
    Oder du gehst rein OOP und benutzt Polymorphie, wie Java in seinen frühen Tagen.

    Bei deinem Beispiel hab ich das Problem, dass ich nicht verstehe was du mit T willst.



  • T ist irgendeine Klasse. Auf das Beispiel bezogen: Eine Klasse die von der Baumstruktur gespeichert und verwaltet wird. Wieder ein schlechtes Beispiel 😉 Vielleicht liegt es daran, dass ich am Abend nicht mehr so klar denken kann, da ich bereits um 4 Uhr aufstehe 🙂



  • Entweder du benutzt generische Programmierung und damit Templates.
    Oder du gehst rein OOP und benutzt Polymorphie

    Generische Programmierung ist ebenfalls eine Art Polymorphie. Einfach eine, die zur Kompilierzeit aufgelöst wird und nicht zur Laufzeit, wie, was du wahrscheinlich unter den Namen Polymorphie verstehst, mit virtuellen Funktionen.



  • Wofür benötige ich dann Templates? Die sind doch für solche Anwendungsfälle da, oder?



  • Nun deine Struktur macht wenig Sinn.

    Wenn dann lieber so:

    template<class T>
    class TreeComponent
    {
    public:
    	TreeComponent() {}
    	virtual ~TreeComponent() {}
    
    	virtual void AddElement(const T&) = 0;
    
    	virtual void DeleteElement() = 0;
    };
    
    template<class T>
    class Node : public TreeComponent<T>
    {
    public:
    	virtual void AddElement(const T& element) {
    		_childs.push_back(element);
    	}
    
    	virtual void DeleteElement() {
    	}
    
    private:
    	std::deque<T> _childs;
    };
    
    template<class T>
    class Leaf : public TreeComponent<T>
    {
    public:
    	virtual void AddElement(const T& element) {
    		data = element;
    	}
    
    	virtual void DeleteElement() {
    	}	
    private:
    	T data;
    };
    


  • Ich verstehe das Problem nicht ganz. Meist ergibt sich die geforderte Typsicherheit von alleine:

    class Foo;
    
    template <class T> class Bar // T muss von Foo abgeleitet sein
    {
    public:
        void Blah()
        {
            Foo* foo = m_t; // implizite Konvertierung nach Foo*
            foo->TuWas();
        }
    
    private:
        T* m_t;
    };
    

    Versuch mal das mit einem T zu instanzieren das nicht von Foo abgeleitet ist...

    ----

    drakon schrieb:

    Du darfst einer Sprache keinen anderen Stil aufzwingen.

    Man darf schon. Ist meist nicht sinnvoll, aber ... manchmal eben doch. In dem Fall vielleicht weniger.



  • hustbaer schrieb:

    ----

    drakon schrieb:

    Du darfst einer Sprache keinen anderen Stil aufzwingen.

    Man darf schon. Ist meist nicht sinnvoll, aber ... manchmal eben doch. In dem Fall vielleicht weniger.

    Ja. Dürfen tut man alles. Ich korigiere mal: "sollen". 🙂



  • hustbaer schrieb:

    Ich verstehe das Problem nicht ganz. Meist ergibt sich die geforderte Typsicherheit von alleine:

    class Foo;
    
    template <class T> class Bar // T muss von Foo abgeleitet sein
    {
    public:
        void Blah()
        {
            Foo* foo = m_t; // implizite Konvertierung nach Foo*
            foo->TuWas();
        }
    
    private:
        T* m_t;
    };
    

    Das kann schon sein, dass in 90% der Fälle die Typensicherheit von Haus aus gesichert ist. Aber wie stellst du sicher, dass eine implizite Konvertierung nach Foo möglich ist? Ich kann ja theoretisch alle mögliche Klassen für T festlegen.

    // Edit: Hätte ich die Möglichkeit T auf eine abstracke Klasse zu beschränken, wäre eine 100% Sicherheit garantiert, sofern diese Klasse eine Methode ToWas() besitzt.

    class Foo;
    
    template <class T> class Bar // T muss von Foo abgeleitet sein
    {
    
    private:
         T* m_t;
    
    public:
        void Blah()
        {
            Foo* foo = this->m_t; // implizite Konvertierung nach Foo*
            foo->TuWas();
        }
    
    private:
        T* m_t;
    };
    


  • wenn die Klasse diese Methode nicht besitzt, kriegst du sowieso einen Compilerfehler. Wenn keine implizite Konvertierung möglich ist, ebenso.



  • JustAnotherNoob schrieb:

    wenn die Klasse diese Methode nicht besitzt, kriegst du sowieso einen Compilerfehler. Wenn keine implizite Konvertierung möglich ist, ebenso.

    🙂 Intressant 🙂

    Danke an alle die hier meinen Beitrag hier lesen mussten und einen Beitrag hierzu geleistet haben 😉



  • Aber wie stellst du sicher, dass eine implizite Konvertierung nach Foo möglich ist?

    3x darfst du Raten was passiert wenn ein Template versucht eine implizite Konvertierung zu machen die nicht möglich ist.




    Natürlich kann man es auch mittels eines BOOST_STATIC_ASSERT(boost::is_base_and_derived<T, U>::value) machen, das ist dann noch etwas expliziter und dokumentiert die Anforderung noch dazu.



  • @hustbear Ich wusste nicht das hier ein Compilezeit-Fehler auftritt 😉 Ich wollte b und c deiner Auswahlmöglichkeiten 100% ausschließen 😉 Zudem dachte ich an den Performancevorteil im ns-Bereich 😃 wenn ich eine implizite Konvertierung nicht durch führen müsste. Dann drinke ich halt einen schlug Kaffee mehr bei der Ausführung 😉


Anmelden zum Antworten