Problem mit Vererbung
-
Hallo zusammen,
ich habe einige Klassen, die ich nicht verändern kann. Ich möchte diese Klassen um eine Funktion (z.B. Output) erweitern. Ich möchte dann diese Funktion in einer Schleife für alle Objekte dieser Klassen aufrufen.
Hier ein Beispiel:class A { protected: int a; }; class B { protected: int b; }; class MyA : public A { public: Output() { cout << a; } }; class MyB : public B { public: Output() { cout << b; } }; TYPE Vector[2]; // <- von welchem Typ muss Vector sein? Vector[0] = new MyA; Vector[1] = new MyB; for (int Idx = 0; Idx < 2; Idx++) { Vector[Idx]->Output(); }Wie gesagt, an A und B kann ich nichts ändern!
Kennt jemand eine Möglichkeit, wie dieses Beispiel funktionieren könnte? Mehrfachvererbung vielleicht?Grüße aus Berlin!
-
Ja, Mehrfachvererbung wäre die einzige Möglichkeit, die mir einfällt:
class IMyClass { public: virtual void Output()=0; }; class MyA : public IMyClass, public A { public void Output() {cout<<a;} } //myB analog ... std::vector<IMyClass*> vec vec.push_back(new MyA); vec.push_back(new MyB); ... for(int i=0;i<vec.size();++i) vec[i]->Output();(eventuell könnte man statt einfachen Vektoren einen Smart-Vektor verwenden)
-
Nach dem Schnittstellen-Prinzip gehören auch alle freien Funktionen, die mit A's oder B's arbeiten zur Schnittstelle der Klasse, sofern sie zusammen mit dieser deklariert werden.
Einfachster Ansatz für dich wäre: Definiere eine Funktion void Output( A&); und packe sie entweder in den Header von A / B sofern du das kannst - oder stell sonst anderwärtig sicher, dass diese Funktion überall dort inkludiert wird, wo auch A / B inkludiert wird.
Edit: Hm meine Lösung klappt wohl nicht ganz, ich habe die Protected-Variablen übersehen.
-
Mehrfachvererbung ist wohl die Lösung. Hilfreich wäre hier noch ein Template als Ergänzung von CStoll:
template <typename T> class MyClassImpl : public IMyClass, public T { public void Output() {cout<<a;} };Dann würde sich die Deklaration von MyA und dem nicht gezeigen MyB erübrigen:
std::vector<IMyClass*> vec vec.push_back(new MyClassImpl<A>); vec.push_back(new MyClassImpl<B>); for (std::vector<IMyClass*>::iterator it = vec.begin(); it != vec.end(); ++it) it->Output();Dabei fällt mir ein, daß die Output-Methode wahrscheinlich als const gemeint ist. Oder aber als freie Funktion, wie 7H3 angedeutet hat.
Tommi
-
tntnet schrieb:
Mehrfachvererbung ist wohl die Lösung. Hilfreich wäre hier noch ein Template als Ergänzung von CStoll:
template <typename T> class MyClassImpl : public IMyClass, public T { public void Output() {cout<<a;} };Dann würde sich die Deklaration von MyA und dem nicht gezeigen MyB erübrigen:
Von dem oberen Beispiel ausgehend, wird das so leider nichts - B (und MyB) hat nämlich kein Element 'a'. Aber ansonsten hast du recht, das wäre die logische Erweiterung meines Vorschlags.
-
Folgendes wäre mir noch eingefallen, hat nur ein dummes Problem...
template <class T, class U, U (T::* member)> class MyClass : public T { void Output() { std::cout << (this->*member); } } .... MyClass<A, int, &A::a> test; test.Output();... und zwar kommt man an &A::a nicht ran, weil es protected ist. Im Kontext der abgeleiteten Klasse sollte das gehen, wie man das aber aufschreibt ist mir noch nicht eingefallen (falls das überhaupt gehen sollte).
-
So ein
aber auch! Eure Lösungen sahen so gut aus!
Ich arbeite (leider!) mit Borlands C++Builder und der beschwert sich, daß VCL-Klassen nicht mehrere Basisklassen haben dürfen. Die Klassen A und B aus meinem Beispiel sind VCL-Klassen und damit auch MyA und MyB.
Hat jemand dafür eine Lösung? Vielleicht gibt es ja eine Borland-like-Lösung.Grüße aus Berlin!
-
Ohne Anspruch auf Erfolg mal eine Idee - wir packen die My*-Klassen in eine Hilfsklassen:
class A { protected: int a; }; class MyA { public: void Output() {cout<<a;} }; //B und MyB analog class wrap_base //damit wir eine gemeinsame Basis haben { }; template<class T> class wrapper : public wrap_base { T m_data; public: wrapper(const T& data=T()) : m_data(data) {} void Output() {m_data.Output();} } ... vector<wrap_base*> vec; vec.push_back(new wrapper<MyA>); vec.push_back(new wrapper<MyB>); ... for(int i=0;i<vec.size();++i) vec[i]->Output();
-
Das wird nen Tick komplizierter, aber nicht unlösbar.
class OutputBase { public: void Output() const = 0; virtual ~OutputBase() {} }; template <class T> class OutputMeth { public: typedef void (T::* MemFun)() const; OutputMeth( T* t, MemFun m) : _t( t), _m( m) {} void Output() const { (t->*m)(); } private: T* _t; MemFun _m; }; template <class T> OutputBase* makeOutputBase( T* t, void (T::* m)() const) { return new OutputMeth<T>(t, m); } struct Deleter { template <typename T> void operator()( T*& t) { delete t; t = 0; } }; ... MyA a; MyB b; std::vector<OutputBase*> vec; vec.push_back( makeOutputBase( &a, &MyA::Output)); vec.push_back( makeOutputBase( &b, &MyB::Output)); // später das delete der Zeiger net vergessen std::for_each( vec.begin(), vec.end(), Deleter());Jetzt muss nur MyXXX eine Methode void Output() const haben, die du durch einfache Vererbung anflanschen kannst.
~Btw, ein tolles Konzept geschweige denn ein zweckgemäßer Einsatz von Vererbung ist das aber nicht.~Edit: Sorry CStoll, dein Post hab ich trotz Klick auf Aktualisieren nicht gesehen. Liegt wohl an unserem Proxy
