Aya - Mo 09.06.08 17:25
Titel: [C++] Mehrfachvererbung
Hi,
ich hab ne frage zu C++ und der möglichkeit der Mehrfachvererbung.. evtl kann mir ja jemand hier helfen :)
(Es geht um C++ nicht C#.. ich benutze nur die C# code-tags ;) )
Also,
ich habe 3 Klassen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| class Main { public: void helloWorld(); };
class A { public: void doSomething(int x); };
class B { public: void doNothing(string s); }; |
und jetzt eine dritte klasse die IMMER von Main ableitet, und zusätzlich manchmal von A und/oder B:
C#-Quelltext
1: 2: 3: 4:
| class AB : public Main, public A, public B { public: ..... }; |
soweit kein problem, aber..
Im code werden die klassen alle als array von Main* gespeichert, aber wenn ich jetzt gern auf die doNothing() funktion zugreifen möchte, wie mach ich das?
Ich ging davon aus, dass ich einfach:
C#-Quelltext
1:
| ((B*)myClass)->doNothing(..); |
verwenden kann, aber das klappt leider nicht, also es kommt dann wohl irgendwie intern durcheinander und ruft falschen code auf...
wenn ich stattdessen schreibe:
C#-Quelltext
1:
| ((AB*)myClass)->doNothing(..); |
geht es, aber die lösung ist für mich eher unpraktisch, da ich halt wie gesagt manchmal auc hnur von A oder B ableite und dementsprechend nicht immer in AB* casten kann...
Die einzige lösung die mir einfiele wären viele if abfragen die überprüfen um welchen typ es sich handelt und dann dementsprechend casten...
Gibt's da irgendwas anderes, besseres?
Aya~
PS: In dem moment wo ich die doNothing() funktion aufrufe weiß ich sicher das das objekt von B geerbt hat, aber ich weiß nicht sicher ob es auch von A geerbt hat = ich kann nicht sicher sagen ob ich nach AB* oder nach BOnly* casten muß..
tommie-lie - Di 10.06.08 11:56
Folgender Code funktioniert bei mir (g++ (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)):
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| #include <iostream>
class Main { public: void helloWorld() { std::cout << "Main::helloWorld" << std::endl; }; };
class A { public: void doSomething(int x) { std::cout << "A::doSomething" << std::endl; }; };
class B { public: void doNothing(float s) { std::cout << "B::doNothing" << std::endl; }; };
class AB : public Main, public A, public B { };
int main() {
Main *ab = new AB(); ab->helloWorld(); ((A*)(ab))->doSomething(23); ((B*)(ab))->doNothing(42);
return 0; } |
und liefert folgende Ausgabe:
Quelltext
1: 2: 3: 4:
| thomas@Majestix:/tmp$ ./a.out Main::helloWorld A::doSomething B::doNothing |
Mehr Typsicherheit erhältst du allerdings durch eine polymorphe Vaterklasse und dynamic_casts:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| #include <iostream>
class Main { public: void helloWorld() { std::cout << "Main::helloWorld" << std::endl; }; virtual ~Main() {}; };
class A { public: void doSomething(int x) { std::cout << "A::doSomething" << std::endl; }; };
class B { public: void doNothing(float s) { std::cout << "B::doNothing" << std::endl; }; };
class AB : public Main, public A, public B { };
int main() {
Main *ab = new AB(); ab->helloWorld(); dynamic_cast<A*>(ab)->doSomething(23); dynamic_cast<B*>(ab)->doNothing(42);
return 0; } |
Getestet und für gut befunden auf dem gleichen System, durch den dynamic_cast sollte auch sichergestellt werden, daß die Methoden tatsächlich existieren, bevor du sie aufrufst.
Wenn A und B selbst wiederum von einer anderen Klasse erben, möglicherweise von einer gemeinsamen Oberlkasse von Main, interessiert dich vielleicht
http://parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.8 und
http://parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9.