Überschreiben von template-Methoden
-
Hallo zusammen.
Irgendwie komme ich hier nicht recht weiter:Oberklasse A, Unterklasse B;
In B wird eine von A geerbte Methode aufgerufen. In dieser Methode wird eine template-Methode aufgerufen, die es in A gibt, die aber auch in B überschrieben wurde.
Warum wird die Methode aus A genommen? Wie kann ich die Verwendung der Methode aus B erreichen?
-
Da Funktionstemplates keine Funktionen sind, können sie nicht virtuell sein. Ich denke die einzige Möglichkeit ist, Dein A in ein B zu casten. Du musst natürlich sicher sein, dass "this" auch ein B ist.
void A::f() { static_cast<B*>(this)->template_func<...>(); }
-
Da die geerbte Methode ja kein template ist wird irgendwo der Punkt kommen, wo du die template-methode mit einem vorgegebenen Typ aufrufst. Um die richtige zu nehmen könntest du eine weitere (virtuelle) Methode definieren, die diese spezielle Templatemethode aufruft:
class A { void f() { this->call_tpl(); } virtual void call_tpl() {tpl_method<int>(5); } template<class T> void tpl_method(T& t) { cout<<"A::tpl_method " << t << '\n';} }; class B { void call_tpl() {tpl_method<int>(5); } template<class T> void tpl_method(T& t) { cout<<"B::tpl_method " << t << '\n';} }; int main() { A a; B b; a.f(); b.f(); }Ist die frage, ob das sinnvolles Design ist, wenn du eine template-methode von einer nicht-templatemethode aufrufen lassen musst.
-
Danke für die Antworten.
Das mit dem Catsen scheint mit nicht zu gehen, da A Oberklasse von B.Vielleicht sollte ich mein Problem etwas konkretisieren:
Es gibt viele Unterklassen B_i und einen Teil von den in allen B_i befindlichen Methoden f habe ich in der Klassenhierarchie nach oben (f' in A) geschoben. Deshalb muss ich von f' aus alle B_i.f aufrufen. Das Problem besteht allerdings darin, dass es Parameter gibt, welche aus Designgründen notwendig sind. Wie kann ich nun A.f'(param_i) aufrufen, sodass hierdurch B.f(param_i) aufgerufen wird, ohne dies für jeden Parametertyp zu implementieren?
Gruß.
-
schreib doch mal ein stück reduzierten beispielcode. der sagt oft mehr als tausend worte mit f, f' usw

-
class S { ... } class S1 : public S { ... } class A { virtual void doIt(S* s)=0; void wrap(S* s) { // Hier sollte irgendwie doIt(...) der entsprechenden Unterklasse (z.B. A1) aufgerufen werden. //Allerdings handelt es sich bei s immer um ein Objekt des Typs S, auch wenn ein S1 übergeben wird, jedoch braucht doIt der Unterklasse ein S1!! ...; } ... } class A1 : public A { void doIt(S1* s1){...;} ... }
-
Was dir scheinbar nicht bewusst sein duerfte: mit A1::doIt(S1*) hast du die abstrakte Methode A::doIt(s*) nicht ueberschrieben sondern nur verdeckt. Beim compilieren wird dein Compiler vermutlich zu recht immernoch meckern, dass es kein A1::doIt(s*) gibt und A1 damit immernoch eine abstrakte Klasse ist (!)
Wenn das doIt von A1 immer nur mit S1 aufgerufen wird, dann ists vielleicht nicht gerade sinnvoll, doIt als virtuelle Methode bereitzustellen bzw. es ist nichtmal unbedingt sinnvoll, hier vererbung einzusetzen. Wenn du uns jetzt noch sagst, was du erreichen willst (A1 und S sind als Namen nicht gerade aussagekraeftig), dann kann man dir vielleicht ein alternatives Design vorschlagen.
Andernfalls waere vielleicht folgendes ein Ansatz:
class S { /*...*/ }; class S1 : public S {/*...*/}; class A { virtual void doIt(S* s)=0; void wrap(S* s) { this->doIt(s); } /*...*/ }; class A1 : public A { void doIt(S1* s) { ps1 = dynamic_cast<S1*>(s); if(!ps1) {/*MIST! s war kein S1*/} else juhu(); } };
-
Also mal danke für die Antwort pumuckl.
Ja, das stimmt: natürlich muss ich auch ein A1::doIt(S* s) anlegen, da A1 nicht abstrakt dein soll. Dann wird aber auch immer diese Methode verwendet und nie A1::doIt(S1* s). Das ist mein Problem... Wie bringe ich das Programm dazu, die spezielle und passende Methode zu wählen?Das alles passiert in einem mathematischen Zusammenhang. Die Modellierung von math. Problemen auf objektorientierte Art und Weise ist eh schon recht verzwickt, deshalb habe ich hier bewusst keine Details erwähnt. Aber ich kann ja mal ein Beispiel konstruieren:
class Loesung // abstrakt { ... } class SpezielleLoesung : public Loesung { ... } class Problem // abstrakt { virtual void loesen(Loesung* s)=0; void initialisieren(Loesung* s) { / ??? ...; } ... } class SpeziellesProblem : public Problem { void loesen(SpezielleLoesung* s1){...;} ... }
-
class A { public: void wrap(S* s) { // ... doIt(s); // ... } void doIt(S* s) { doItImpl(s); } private: virtual void doItImpl(S* s)=0; }; class A1 : public A { private: virtual void doItImpl(S* s) { S1* s1 = dynamic_cast<S1*>(s); assert(s1); doItWithS1(s1); } void doItWithS1(S1* s) { } };Ansonsten: double dispatch aka. visitor pattern
-
Vielen dank an Euch beide! Durch das Stichwort dynamic_cast bin ich auf folgendes gekommen:
class A { public: void wrap(S* s) { // ... doIt(s); // ... } private: virtual void doIt(S* s)=0; }; class A1 : public A { private: virtual void doIt(S* s) { S1* s1 = dynamic_cast<S1*>(s); assert(s1); doItWithS1(s1); } void doIt(S1* s) { } };Die zusätzlich benötigte Methode A1::doIt(S* s) werde ich halt für die Behandlung von falschen Parametern mitbenutzen.
Viele Grüße.