Klasse beinhaltet Objekte einer anderen Klasse, wie?
-
ich bin so blöd... kaum Programmiere ich mal ne Woche net, vergess ich alles was ich beim letzten mal noch wusste...
net c1::display, sondern c1.display

danke unskilled

-
Lanfear schrieb:
Initialisierungslisten? nie gehört, mein Buch gibt dazu auch nix her (im index net zu finden
)Initialisierungslisten sind eigentlich der Weg wie man in C++ Klassen initialisieren sollte. Aber dazu gleich noch etwas mehr...
Lanfear schrieb:
komrad (int zre, int nre, int zim, int nim) { komrad::re(zre, nre); komrad::im(zim, nim);}Der Sinn war, das den Objekten re und im die Zahlen übergeben werden, ich hoffte das er dann den entsprechenden Konstruktor aufruft.
Innerhalb der Methoden der Klasse sind die Membervariablen bekannt. Sprich, dort ist nichts vor den Bezeichner zu setzen, es sei den bei Namenskonflikten, dann wird aber über den this-> Zeiger zugegriffen, nicht über den Klassennamen.
Lanfear schrieb:
Ein Problem, das ich jetzt noch habe iss, das ich net weiß wie ich auf die Elemente meiner "Unterklassen" zugreifen kann.
Lass den Begriff Unterklasse hier lieber weg, ebenso wie Vererbung. Den hier wird keine Vererbung verwendet.
So... nun aber nochmal genauer:
//... // Kleine Bitte: gewöhn dir Abkürzungen ab. Sonst verstehst du deinen // eigenen Code später nicht mehr. Mit komrad würde ich auf Anhieb nichts // anfangen ebenso wie mit re und im, es sei den irgendwer liefert eine // Beschreibung mit. Außer deiner Schreibfaulheit ist hier niemanden // geholfen... Lesbarer Code verringert den Dokumentierungsbedarf und fördert // die Wartbarkeit. class komrad { private: bruch re, im; public: komrad(int zre, int nre, int zim, int nim); //...Es gibt nun zwei Varianten den Konstruktor umzusetzen. Die erste Variante ist suboptimal (Ich verwende in beiden Fällen die Schreibweise wie man die Methode bei trennung von Deklaration [.h] und Definition [.cpp] schreiben würde):
komrad::komrad(int zre, int nre, int zim, int nim) { // 1. Hier ist bereits die Initialisierung passiert! // Hier kannst du daher nicht mehr initialisieren sondern nur zuweisen! // 2. Zugriff über den Membernamen... re = bruch(zre, nre); // 3. Du kannst auch über den this-> Zeiger gehen... this->im = bruch(zim, nim); }Besser:
komrad::komrad(int zre, int nre, int zim, int nim) : re(zre, nre), // Hier erfolgt tatsächlich eine Initialisierung im(zim, nim) { //<> Name der Membervariablen // <------> Initialisierungswert // Achtung: Die gleiche Reihenfolge wie in der Memberdeklaration verwenden, // um nicht unschöne Seiteneffekte bei gegenseitigen Abhängigkeiten // zu erhalten }Diese Schreibweise hat folgende Vorteile:
a) Auch Konstanten und Referenzen lassen sich so initialisieren
b) Es erfolgt eine Initialisierung (Nicht wie im ersten Beispiel eine initialisierung mit dem Standardkonstruktor, und einer anschließenden Zuweisung).
c) Über die Initialisierungsliste lassen sich auch andere Konstruktoren als der Standardkonstruktor von Basisklassen (im Falle der hier nicht vorliegenden Ableitung) verwenden.Vielleicht hier noch etwas zur Begrifflichkeit:
class A : public B {}; // Vererbung, "A ist ein B", A leitet von B ab class C { private: D d; // Komposition, "C enthält/hat ein D" };So... nun erhöhen wir den Schwierigkeitsgrad ein wenig. Nehmen wir an deine Klasse bekommt noch einen Konstruktor, der direkt mit zwei Brüchen arbeitet. Und zudem nennen wir die Parameter noch genau so, wie die Membervariablen...
class komrad { //... public: komrad(int zre, int nre, int zim, int nim); komrad(bruch const & re, bruch const & im); //...Wie müssen wir nun vorgehen?
// Variante 1: Mittels nachträglicher Zuweisung. komrad::komrad(bruch const & re, bruch const & im) { // Nun ist der this-> Zeiger zwingend zu verwenden... this->re = re; this->im = im; //<------> Zugriff auf Member // <> Zugriff auf Parameter } // Variante 2: Mittels Initialisierungsliste komrad::komrad(bruch const & re, bruch const & im) : re(re), // Aufruf des Kopierkonstruktors... im(im) { //<> Name der Membervariablen (Kein this!) // <> Name des Parameters }Nur als ergänzung:
bruch const & re
ist identisch mit
const bruch & reUnd bedeutet, das du eine konstante Referenz (einen Aliasnamen) übergibst. Im Gegensatz zu der Schreibweise ohne "const &" vermeide ich hier eine unnötige Objektkopie.
cu André
-
Hallo

vielen Dank für die Erklärungen, asc

Ich muss sagen, aber wirklich sicher das ich alles verstanden hab bin ich net ^^
Aber, das stelle ich erstmal hinten an.funktionieren tut es aber... ^^
komrad (bruch const & kre, bruch const & kim) : re (kre), im(kim) {} komrad (bruch const & kre) :re (kre), im(0,0) {} // ... bissle mehr geschreibsel, in der main steht dann: komrad brueche_uebergeben=komrad(b1, b2); brueche_uebergeben.display(); cout << endl << "_____________________________________" << endl; komrad bruch_uebergeben=komrad(b3); bruch_uebergeben.display(); cout << endl << "_____________________________________" << endl;Ausgabe: 1/2+3/4i bzw. 4/4+0/0i

Das gleiche habe ich inzwischen auch für die Klasse bruch verwirklicht, dieser kann ich nun einfach ein Objekt der Klasse bruch übergeben:
bruch (const bruch& a) {zaehler=a.zaehler; nenner=a.nenner;} // in der main: b1.displaybruch(); b2.displaybruch(); b1=b2; b1.displaybruch(); b2.displaybruch();Ausgabe: b1: 1/2 b2: 3/4 -- b1: 3/4 b2: 3/4
soweit ok.
mein nächstes Problem ist, das ich in der Klasse bruch einen Konstruktor bauen will, dem ich ein Objekt der Klasse komrad übergeben kann, und er sich dann den Realteil herrauszieht.Das hätte ich auf 2 Arten lösen wollen... (ka welcher funktioniert ^^)
bruch (komrad blubb) { int hilfszaehler=0, hilfsnenner=0; hilfszaehler=blubb.get_rezaehler(); hilfsnenner=blubb.get_renenner(); set(hilfszaehler, hilfsnenner); }oder ... halt mit dem kopierkonstruktor irgendwie...
bruch (komrad const & uebergeben) { // Nun ist der this-> Zeiger zwingend zu verwenden... this = uebergeben.re; //<------> Zugriff auf Member // <> Zugriff auf Parameter }nur, ich vermute das Problem liegt darin, das die Klasse komrad erst nach der Klasse bruch definiert wird (also der Kompiler nicht weiß das es sich bei komrad um eine Klasse handelt) und daher Fehler ausspuckt.
Fehler 1 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 2 error C2228: Links von ".re" muss sich eine Klasse/Struktur/Union befinden.Ich weiß wie ich Funktionen vorstelle das der Compiler weiß das noch eine Funktion mit diesem Namen kommt, aber wie mache ich bei Codebeginn Klassen bekannt?
ich habs mit
class komrad;versucht, aber in allen Variationen geht das net.
wenn ihr wollt kann ich auch mal den kompletten Code reinstellen, aber der iss etwas länger... (550 Zeilen), da sich durchwurschteln zu müssen wird net schön

-
*edit* falsch gelesen, sry ^^
-
ähm, ich bin jetzt net sicher was du verstanden hast....
also ausführlich.
Ich habe 2 Klassen. Klasse bruch besteht ja aus dem Zähler und Nenner eines Bruchs (als int-variablen). Die Klasse komrad beinhaltet 2 Brüche, jeweils einen für den Realteil (re) und dem Imaginärteil der Zahl.
komrad: re+im
wobei re und im jeweils objekte der Klasse bruch sind.bruch: zaehler und nenner
wobei diese als int drinneliegen.wenn ich jetzt einem Objekt bruch ein Objekt komrad als zuweisung übergebe, dann soll den variablen zaehler und nenner der entsprechende zaehler und nenner von re (der Klasse komrad) übergeben werden/benutzt werden und der imaginärteil wegfallen.
bsp:
class bruch { private: int zaehler, nenner; public: // [...] class komrad { private: bruch re, im; public: // [...] //in der main dann: komrad k1=komrad (1,2,3,4) bruch b1=bruch (1,1) b1=k1; b1.display(); // [...]so schaut es vor b1=k1; aus:
k1: 1/2+3/4i
b1: 1/1nach b1=k1 soll folgendes rauskommen:
b1: 1/2
(und der imaginärteil wird einfach net benutzt)zumindest hab ich das so verstanden was der nette Herr von mir will:
● Ergänzen Sie zur Typumwandlung Cast-Funktionen (z.B. über
Typumwandlungs-Konstruktoren) von der Klasse KompRat zur Klasse
Bruch und umgekehrt. Bei der Verwandlung zum Bruch wird der
Imaginär-Teil verworfen. Bei der Verwandlung zur „komplexen rationalen
Zahl“ wird der Imaginärteil auf Null initialisiert.wenns hilft kann ich auch den ganzen Code mal posten...
-
unskilled schrieb:
mein nächstes Problem ist, das ich in der Klasse bruch einen Konstruktor bauen will, dem ich ein Objekt der Klasse komrad übergeben kann, und er sich dann den Realteil herrauszieht.
Versteh ich nicht - du willst also nicht das gesamte Objekt kopieren, sondern nur den Realteil?
Falls ich das richtig verstanden habe, wäre hier der Kopierkonstruktor nicht geeignet und du solltest ne eigene Funktion dafür schreiben, da der Kopierkonstruktor dazu da ist, das gesamte Objekt zu kopieren...bb
Ein Konstruktor von bruch der ein komrad als Argument nimmt hat auch nichts mit einem Kopierkonstruktor zu tun...
folgende Möglichkeiten gibts bei der Bruch-Klasse die du oben beschrieben hast:
bruch(komrad const& kom) { set(kom.getRe().zaehler, kom.getRe().nenner); } //Variante1 mit direktem Aufruf von set bruch(komrad const& kom) { *this = bruch(kom.getRe()); } //Variante2 mit Aufruf des Kopierkonstruktors von bruch, also indirekter Aufruf von set bruch(komrad const& kom) : zaehler(kom.getRe().zaehler), nenner(kom.getRe().nenner) {} //Variante3 mit InitialisierungslisteAllerdings brauchen alle drei versionen Zugriff auf den Realteil von komrad, daher sollte die Klasse komrad entweder eine Funktion wie getRe() definieren die den Realteil zurückgibt, oder sie sollte den Konstruktor von bruch zum Friend machen.
-
von bruch auf komrad hab ich das so gelöst:
class komrad { private: bruch re, im; public: komrad (int zre, int nre, int zim, int nim) : re (zre, nre), im (zim, nim) {} komrad (bruch const & kre, bruch const & kim) : re (kre), im(kim) {} //hier die wichtige Zeile: wenn die klasse komrad nen bruch bekommt, initialisiert sie re mit dem bruch, und im wird mit (0,0) initialisiert. komrad (bruch const & kre) :re (kre), im(0,0) {}damit kann ich entweder einer komrad einen bruch zuweisen oder komrad mit einem bruch initialisieren:
// in der main dann: bruch b1=bruch(1,2); bruch b2=bruch(3,4); bruch b3=bruch(4,5); komrad brueche_uebergeben=komrad(b1, b2); brueche_uebergeben.display(); komrad bruch_uebergeben=komrad(b3); bruch_uebergeben.display(); a=b1; a.display();was zu folgender Ausgabe führt:
brueche_uebergeben: 1/2+3/4i
bruch_uebergeben: 4/5+0/0ia.display: 1/2+0/0i
das geleiche soll jetzt auch für bruch möglich sein, dem ein komrad gegeben wird.
-
die get-funktionen hab ich:
public: [...] hier stehen die konstruktoren int get_imzaehler () { int a=0; return a=im.get_zaehler(); } int get_imnenner () { int a=0; return a=im.get_nenner(); } int get_rezaehler () { int a=0; return a=re.get_zaehler(); } int get_renenner () { int a=0; return a=re.get_nenner(); } bruch get_re () { return re;} bruch get_im () { return im;}ok, sind vielleicht umständlich, aber sie funktionieren (glaub ich ^^)
edit: get_re und get.im hinzugefügt....es bleibt aber immernoch bestehen, das ich folgende Fehler bekomme:
Fehler 1 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 2 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.
-
Ich habe jetzt alle 3 von Pumuckl vorgeschlagenen Varianten ausprobiert, doch bei jeder erhalte ich folgende Fehler:
ich habe die Klasse komrad vorrangestellt, weiter unten iss der Anfang meines Codes.Variante 1:
bruch(komrad const& kom) { set(kom.getRe().zaehler, kom.getRe().nenner); } //Variante1 mit direktem Aufruf von setFehler 1 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 2 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.
Fehler 3 error C2228: Links von ".zaehler" muss sich eine Klasse/Struktur/Union befinden.
Fehler 4 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 5 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.
Fehler 6 error C2228: Links von ".nenner" muss sich eine Klasse/Struktur/Union befinden.Variante 2:
bruch(komrad const& kom) { *this = bruch(kom.getRe()); } //Variante2 mit Aufruf des Kopierkonstruktors von bruch, also indirekter Aufruf von setFehler 1 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 2 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.Variante 3:
bruch(komrad const& kom) : zaehler(kom.get_re().zaehler), nenner(kom.get_re().nenner) {}Fehler 1 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 2 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.
Fehler 3 error C2228: Links von ".zaehler" muss sich eine Klasse/Struktur/Union befinden.
Fehler 4 error C2027: Verwendung des undefinierten Typs "komrad"
Fehler 5 error C2228: Links von ".get_re" muss sich eine Klasse/Struktur/Union befinden.
Fehler 6 error C2228: Links von ".nenner" muss sich eine Klasse/Struktur/Union befinden.so sieht derzeit der Anfang meines Codes aus:
#include <iostream> using namespace std; class komrad; class bruch { private: int zaehler, nenner; public: bruch (int z,int n) {set (z, n);} bruch (int zaehler) {int nenner=1; set(nenner, zaehler);} bruch (const bruch& a) {zaehler=a.zaehler; nenner=a.nenner;} // eigener Versuch: //bruch (komrad blubb) //{ // int hilfszaehler=0, hilfsnenner=0; // hilfszaehler=blubb.get_rezaehler(); // hilfsnenner=blubb.get_renenner(); // set(hilfszaehler, hilfsnenner); //} //bruch(komrad const& kom) { set(kom.get_re().zaehler, kom.get_re().nenner); } // Variante 1 //bruch(const komrad& a) { *this = bruch(a.get_re()); } // Variante 2 //bruch(komrad const& kom) : zaehler(kom.get_re().zaehler), nenner(kom.get_re().nenner) {} // Variante 3 ~bruch (){/*cout << "Destructing bruch " << zaehler << "/" << nenner << endl;*/} [...] jede Menge weiterer Zeilen Code ....
-
In der Fehlermeldung steht ja, dass du einen nicht definierten Typ verwendest. Die Klasse
komradmuss hier vollständig bekannt sein, eine Vorwärtsdeklaration reicht nicht.
-
naja, aber irgendwas muss als erstes stehen.
Ich verwende bruch in der klasse komrad, genauso wie ich komrad in der Klasse bruch verwende...
Da beißst sich die Schlange selbst in den Schwanz
schau:
meine Klasse bruch steht ja oben...
und genauso isses auch in der Klasse komrad:[...] // Klasse bruch usw. class komrad { private: bruch re, im; public: komrad (int zre, int nre, int zim, int nim) : re (zre, nre), im (zim, nim) {} komrad (bruch const & kre, bruch const & kim) : re (kre), im(kim) // Aufruf des Kopierkonstruktors... {} //<> Name der Membervariablen (Kein this!) // <> Name des Parameters komrad (bruch const & kre) :re (kre), im(0,0) {} ~komrad(){} [...] // jede Menge Code :)Ich habs ausprobiert, ich hab komrad vor bruch gestellt, nur dann krieg ich die Fehlermeldungen bei komrad, weil bruch net bekannt iss

-
Das ist nicht so gut, wenn sich die beiden Klassen gegenseitig verwenden. Wofür braucht ein Bruch eine komplexe Zahl zu kennen? Ich denke, du willst ja in der komplexen Zahl zwei Brüche (Real- und Imaginärteil) speichern, die ja selber reell sind.
Abgesehen davon teilt man Klassen normalerweise in Schnittstelle (Klassendefinition, Deklaration der Memberfunktionen) und Implementierung (Definition der Memberfunktionen auf). Die Schnittstelle befindet sich in einer Headerdatei (.h/.hpp), die Implementierung in einer kompilierbaren C++-Datei (.cpp).
-
ich hab keine Ahnung was normal iss, und ich hab keine Ahnung, warum grade die komrad 2x bruch beinhalten soll.
Was ich aber weiß iss, das es die Aufgabenstellung des Professors iss.
● Ergänzen Sie zur Typumwandlung Cast-Funktionen (z.B. über
Typumwandlungs-Konstruktoren) von der Klasse KompRat zur Klasse
Bruch und umgekehrt. Bei der Verwandlung zum Bruch wird der
Imaginär-Teil verworfen. Bei der Verwandlung zur „komplexen rationalen
Zahl“ wird der Imaginärteil auf Null initialisiert.
-
Nun will ja schon die Aufgabenstellung, dass du in beiden Klassen einen Copy-Konstruktor für die jeweils andere Klasse hast, wenn ich mir das genau genug durchgelesen habe. Da bleibt nichts anderes, als die Implementierung in ein Modul (eine neue .cpp) auszulagern. Solange in der Deklaration nur die Referenzen verwendet werden, kommst du mit Vorwärtsdeklaration aus.
-
Danke für die Idee

Leider gab es sowas bisher net in ner Vorlesung, auch das Script geht hierauf nirgends ein, genauso wenig mein Buch. Ich glaube auch kaum, das der Prof es sich so vorgestellt hat (es wäre schon sehr weit von den Themen weg, die wir in der Vorlesung behandelt haben und noch behandeln werden).
Es kann aber gut sein, das die Kommunikation zwischen meinem Prof und seinem Hiwi etwas... gehinkt hat, wär net das erste mal ^^
Ich werd morgen mal den Prof selbst dazu fragen, das hat bisher immer Früchte getragen.
meanwhile... wenn jemand noch ne Idee hat, immer her damit
