Templates und Interface
-
Ich habe eine Template Klasse, welche NUR mit Objekten arbeiten kann, die von einem bestimmten Interface abgeleitet sind, also eine bestimmte Mehode implementieren.
Möglichkeit 1 (#1):
Ich kann bereits verhindern, das eine Templateklasse mit einem Objekttyp ertsellt werden kann, das nicht von Interface abgeleitet wurde. Falls das möglich ist, wie?Möglichkeit 2 (#2):
Die Methode selbst kann erkennen, das ein bestimmtes Objekt diese benötigte Methode nicht implemetiert. Falls das möglich ist, wie?class Interface { public: virtual int foo(); }; class C1 : public Interface { public: int foo() { /* do something */ } }; class C2 public: /* ... */ }; template <class T> class TemplateClass { public: void do(T& object) { Interface& i = (Interface&)object; int n = i.foo() = ; /* work with n */ } }; int main() { TemplateClass<C1> tc1; TemplateClass<C2> tc2; // #1 C1 c1; C2 c2; tc1.do(c1); tc2.do(c2); // #2 }
-
Hmm ... abstrakte Basisklasse ... (Interface) davon dann C1 ableiten ... Funktionen der Basisklasse überschreiben ... aus TemplateClass ne normale Klasse (kein template) machen ... do in action umbennen (do ist ein Keyword in C++) ... action als Parameter einen Zeiger auf ein Interface übergeben.
-
Backus schrieb:
Möglichkeit 1 (#1):
Ich kann bereits verhindern, das eine Templateklasse mit einem Objekttyp ertsellt werden kann, das nicht von Interface abgeleitet wurde. Falls das möglich ist, wie?das ist möglich.
ein moderner compiler und boost sind voraussetzungen:
#include <tr1/type_traits> #include <boost/static_assert.hpp> class Base {}; class Derived : public Base {}; class NonDerived {}; template <class T> class Test { BOOST_STATIC_ASSERT( (std::tr1::is_base_of<Base, T>::value) ); };andernfalls kannst du dir quick und dirty natürlich selbst sowas wie BOOST_STATIC_ASSERT zusammenschustern.
template <bool> class static_assertion_t; template <> class static_assertion_t<true> {}; #define MY_STATIC_ASSERT(x) static_assertion_t<x> static_assertion; //... template <class T> class Test { MY_STATIC_ASSERT ((is_base_of<Interface, T>::value)); };oder so.
-
Übrigens solltest du bei Templates nicht zu eng auf die Verwandschaftsverhältnisse achten - normalerweise reicht es aus, daß ein Typ bestimmte Operationen/Methoden unterstützt. Das heißt in deinem Beispiel, das Template schluckt alle Typen, die konvertierbar nach "Interface" sind (entweder weil sie damit verwandt sind oder weil sie einen Umwandlungsoperator definiert haben) - wenn du den Methodenanfang ersetzt durch "int n = object.foo();", schluckt sie sagar alles, was eine passende foo()-Methode mitbringt.
-
Backus schrieb:
Ich habe eine Template Klasse, welche NUR mit Objekten arbeiten kann, die von einem bestimmten Interface abgeleitet sind, also eine bestimmte Mehode implementieren.
Von einem Interface abgeleitet zu sein und eine bestimmte Methode zu implementieren sind zwei verschiedene Paar Schuhe. Wenn die benutzte Klasse wirklich von einer bestimmten Basisklasse abgeleitet sein soll, reichen die oben genannten Mittel. Wenn die Klasse nur eine Methode bestimmten Namens definieren muss, dann reicht es, das völlig ohne jede Überprüfung zu machen. Wenn man nämlich versucht, dem Template eine Klasse zu übergeben die diese Methode nicht definiert, wirds schon beim Compilieren eine entsprechende Fehlermeldung geben und gut ist.