Templates und OOP
-
Entweder du benutzt generische Programmierung und damit Templates.
Oder du gehst rein OOP und benutzt PolymorphieGenerische 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 
-
Also ich hab' jetzt nicht im Standard nachgelesen ob ein Compiler hier einen Fehler melden MUSS, aber ich habe noch nie mit einem Compiler gearbeitet der hier keinen Fehler melden würde.
Was die Laufzeit angeht ist es egal - ich denke man kann davon ausgehen dass eine unnötige (explizite oder implizite) Konvertierung eines Zeigers wegoptimiert wird.
Das einzige was mir hier einfällt was wohl nicht wegoptimiert werden kann (und sollte) ist ein downcast mit reinterpret_cast und Referenzen (denn hier müsste ein Runtime-Check erfolgen der u.u. einen bad_cast werfen müsste - ein Wegoptimieren verbietet sich also da dann ja im Falle des Falles kein bad_cast mehr fliegen würde).
Aber egal. Wenn boost::is_base_and_derived das macht was du willst, dann verwende es. Hat wie schon gesagt den Vorteil dass es die Anforderung auch besser dokumentiert als eine implizite Konvertierung irgendwo. Und dass der Fehler sofort bei der Instanzierung des Klassen-Templates, und nicht erst bei der Instanzierung irgendeiner Methode des Klassen-Templates gemeldet wird.