Objekt einer Klasse in Klasse verwenden
-
Ich habe hier zwei Klassen, wobei ich die Funktionen der ersten Klasse in der zweiten benötige.
Wie kann ich das machen?
-
amolacar schrieb:
Ich habe hier zwei Klassen, wobei ich die Funktionen der ersten Klasse in der zweiten benötige.
Wie kann ich das machen?Es gibt viele Möglichkeiten. Die technische Umsetzung sollte sich jedoch an der Modellierung orientieren, niemals umgekehrt. Was sollen deine Klassen darstellen, wie verhalten sich die Klassen und Objektinstanzen zueinander?
-
So:
#include <iostream> class A { int i_; public: A(int i) : i_(i) {} void foo() { std::cout << i_ << '\n'; } }; class B { A a_; public: B(int i) : a_(i) {} void foo() { a_.foo(); } }; int main() { B b(5); b.foo(); }
-
@cooky451: Woher weißt du, dass er Komposition suchte, nicht Vererbung (in einer ihrer vielen Spielarten), Übergabe (in einer ihrer vielen Spielarten) oder sonstwas, das ich gerade vergessen habe (in einer seiner vielen Spielarten)?
-
SeppJ schrieb:
Es gibt viele Möglichkeiten. Die technische Umsetzung sollte sich jedoch an der Modellierung orientieren, niemals umgekehrt. Was sollen deine Klassen darstellen, wie verhalten sich die Klassen und Objektinstanzen zueinander?
Genauer: Ich habe eine Klasse, die die socket-Funktionen der Win-API durch eigene Methoden ersetzt, dazu Fehlerbehandlung etc..
Das hat den Sinn, dass ich in der zweiten Klasse dann zum Beispiel nur noch createSocket() aufrufen muss wenn ich eins erstellen will.
-
SeppJ schrieb:
@cooky451: Woher weißt du, dass er Komposition suchte, nicht Vererbung (in einer ihrer vielen Spielarten), Übergabe (in einer ihrer vielen Spielarten) oder sonstwas, das ich gerade vergessen habe (in einer seiner vielen Spielarten)?
Ich hab ihm einfach irgendwas geschrieben damit er einsieht, dass die Informationen nicht reichen. Geht meiner Erfahrung nach schneller als Diskussionen.
amolacar schrieb:
Genauer: Ich habe eine Klasse, die die socket-Funktionen der Win-API durch eigene Methoden ersetzt, dazu Fehlerbehandlung etc..
Das hat den Sinn, dass ich in der zweiten Klasse dann zum Beispiel nur noch createSocket() aufrufen muss wenn ich eins erstellen will.Such mal nach RAII.
-
RAII klingt auf jeden Fall interessant, wird hier meiner Meinung nach nicht benötigt.
Um nochmal zurück zu meiner Frage zu kommen:Wie kann ich diese "socket-Klasse" jetzt in meiner zweiten Klasse nutzen?
-
amolacar schrieb:
RAII klingt auf jeden Fall interessant, wird hier meiner Meinung nach nicht benötigt.
Nur auf die Art und Weise, wie ein Flugzeug nicht "nötig" ist, um von London nach New York zu kommen. Es mag auch ohne gehen, ist dann aber unnötig langsam und umständlich. Guck dir das unbedingt nochmal an. Das ist eine wichtige Grundtechnik!
Wie kann ich diese "socket-Klasse" jetzt in meiner zweiten Klasse nutzen?
Die Frage erübrigt sich, wenn die Klassen ihre Ressourcen selber verwalten, siehe oben.
-
wie meine voredner schon sagten: was hast du genau vor?
(Used sei im foglenden die zu nutzende Klasse, User die nutzende Klasse):
1.- du kannst User von Used erben lassen um die funktionalität zu nutzenclass Used { }; class User : public/private/protected Used {};2.- du kannst Used in User reinkomponieren
class Used { }; class User { Used m_used; };3.- du kannst dir innerhalb von methoden lokal ein Used objekt erstellen und dieses dann nutzen
class Used { }; class User { void foo() { Used u; } };das sind 3 grundlegende möglichkeiten, es geht noch mehr, aber rück erstmal infos raus

-
SeppJ schrieb:
@cooky451: Woher weißt du, dass er Komposition suchte, nicht Vererbung?
Aus dem Titel zu entnehmen.
-
Aber er kann auch eine noch schwächere Bindung gebrauchen:
class A { public: void foo(); }; class B { public: B() : a(nullptr) {} void SetA(A& a) {this->a = &a;} void func() {a->foo();} private: A* a; };oder sogar
class A { public: void foo(); }; class B { public: void someFunc(A& a) {a.foo();} };
-
Müsste es nicht so heißten:
[cpp]void SetA(A***** a) {this->a = a;} [/cpp]MfG
-
jain, er kann einen zeiger als parameter argument erwarten oder eine referenz, aber im falle der referenz (wie ers gemacht hat) muss er dann seiner membervaraible die addresse geben:
class A { public: void foo(); }; class B { public: B() : a(nullptr) {} void SetA(A& a) {this->a = &a;} // <---- void SetA(A * a) {this->a = a;}; void func() {a->foo();} private: A* a; };
-
Das war eigentlich eine Übung an den TE, aber da ihr es jetzt schon aufgelöst habt, hab ich es ebenfalls korrigiert.

yihaaa: Das ist eine semantische Frage. Ich finde die Referenzübergabe sinnvoller, weil ich meistens bei Dependency Injection nicht im Nachhinein einen Zeiger ungültig machen möchte. Soll man das nicht können, dann ist die Referenz zur Indikation dessen angebrachter, wie ich finde.
-
Ja die Übergabe per Referenz ist natürlich besser, da sie weniger Fehleranfällig ist als die mit Pointer. Wie schnell hat man mal das dereferenzieren vergessen...
Sorry, das wir deine Übung versaut haben
MfG
-
Erstmal vielen Dank für die tolle und kompetente Hilfe.
Ich habe mir das mit der RAII nochmal genauer angeguckt und wollte hier nochmal erläutern wie ich das verstehe:Wenn ich von meiner Socket-Klasse ausgehe erstelle ich mit jedem Objekt einen Socket, diesen kann ich dann mit Methoden verändern (an einen Port binden etc.) und durch den Destruktor in dem ich den Socket wieder freigebe wird automatisch, wenn ich z.B. ein Socket-Objekt in einer Methode in der Klasse in der ich die Socket-Klasse verwenden möchte erzeuge, dieses Objekt freigegeben, da mit dem verlassen der Funktion auch alle Variablen und Objekte zerstört werden?
Ist das so richtig?
-
Genau. Im Konstruktor erstellst du den Socket, und im Destruktor zerstörst du ihn wieder. Dann kannst du das nicht vergessen, und der Code ist Exception sicher. Wie genau man das jetzt modelliert könnte noch eine andere Frage sein, (connection/server/..) aber ich denke das bringt dir hier erstmal nicht genug Vorteile. Hauptsache RAII ist drin. Und vergiss den copy Konstruktor und den Zuweisungsoperator nicht.
(Wohl einfach private machen. Eventuell mal nach C++11 move suchen.)
-
Okay es hat sich ein weiteres Problemchen ergeben wo ich nochmal eure Hilfe brauche.
Als privat deklariert:
SOCKET _sockDas ist mein Konstruktor:
Socket::Socket() : _sock(socket(PF_INET, SOCK_STREAM, 0)) { if (_sock == INVALID_SOCKET) { throw socketException("socket() failed", WSAGetLastError()); } }Der Destruktor:
Socket::~Socket() { error = closesocket(_sock); if (error == SOCKET_ERROR) { throw socketException("closesocket() failed", WSAGetLastError()); } }Der Programmcode in dem der Fehler auftritt:
Socket saccept; Socket slisten; slisten.bind(SERVER_PORT, SERVER_ADDRESS); slisten.listen(); do { saccept.accept(slisten); } while (1);Nachdem die erste Verbindung aktzeptiert wurde und der erste Schleifendurchlauf beendet wurde bekomme ich eine Exception geworfen die mir sagt, dass closesocket() fehlgeschlagen ist mit dem Fehlercode 10038.
Kann mir jmd sagen was ich falsch mache?
-
da ich mich mit sockets nicht auskenne, kann ich nur eine schwere falle aufdecken.
NIEMALS IN DESTRUKTOREN EXCEPTIONS WERFEN !!!
ansonsten kann es passieren, dass objekte (oder arrays/vectoren) nicht komplett zerstört werden (oder im falle von arrays/listen einige nicht destruiert werden)
genaueres in effective c++ nachzulesen
-
Oha, gut zu wissen, danke.
Trotzdem frage ich mich, wieso nach dem ersten Schleifendurchlauf der Destruktor aufgerufen wird.Edit: Habe die Exception mal rausgenommen, jetzt wird nachdem die erste Verbindung aktzeptiert wurde gar keine Verbindung mehr angenommen, es wird aber auch keine Exception geworfen.