[gelöst] Aufruf einer Basisklassenfunktion; früher: was darf friend?
-
Wenn teil abstrakt sein soll, dann definiere es auch so:
class teil { public: virtual void print()=0;//abstrakte Methode - von Nachkommen definiert }; class mutter : public teil { public: virtual void print() { cout <<"Mutter:"<<irgendwas; } }; ... teil* pt = new mutter; pt->print();
-
@CStoll:
pefekt! Das ist sozusagen das i-Tüpfelchen!
Danke Euch allen!Christian
-
ChrisPHL schrieb:
...
Ich will also lieber, dass die class teil {}; eine abstrakte Basisklasse ist (Das sollte sie eigentlich sein)....Also ich muss sagen, dass ich das sanft anzweifele ... die Namensgeben lässt mich vermuten, dass es sich um "Teil" und um einen "Teilverwalter" handelt.
Mit Vererbung (also "Basisklasse") setzt man oft einen "Ist-ein-"-Beziehung um ... und "Ist ein Teilverwalter ein Teil" ?
Wirklich ? Kann man mit dem Verwalter alles machen, was man mit dem Teil auch machen kann ?Ich vermute eher, dass Du eine "Hat-eine/mehrere"-Beziehung zwischen beiden hast ... und die solltest Du über "Aggregation" umsetzen (s.o. "Hat ein").
Wenn Dein Problem ist, dass der Verwalter erst "im Laufe seines Lebens" Teile erzeugt, kannst Du sie in einem vector ablegen..class tverw { std::vector<Teil> teile; public: virtual void erzeugeTeil() { teile.push_back(Teil()); } };BTW: "virtuelle Basisklassen" sind wichtig bei Mehrfachvererbung (wenn also eine Klasse von unterschiedlichen Klassen erbt) .... ich glaube auch hier nicht, dass es das ist, was Du wirklich willst.

Gruß,
Simon2.
-
Ob du es glaubst oder nicht, genau das ist es aber, was ich will... bzw. die Aufgabenstellung vorgibt. Klasse 'tverw' ist die einzige, die von außen aus der main() erreichbar/ benutzt werden soll. Diese fängt dann an, einzelne Teile (Klasse 'teil') aus einer von der main() angegebenen DatenDatei.
Trotzdem Danke für deine Hilfe, man lernt eben nie aus...
Gruß
Christian
-
ChrisPHL schrieb:
Ob du es glaubst oder nicht, genau das ist es aber, was ich will... bzw. die Aufgabenstellung vorgibt. ...
Glaube ich immer noch nicht.

ChrisPHL schrieb:
Klasse 'tverw' ist die einzige, die von außen aus der main() erreichbar/ benutzt werden soll. Diese fängt dann an, einzelne Teile (Klasse 'teil') aus einer von der main() angegebenen DatenDatei. ....
(ich tippe mal drauf, dass da noch ein "erzeugt" kommen sollte)
Nochmal die Frage: "IST tverw ein teil ?"
Wenn also z.B. tverw von teil erbt ... hat dann teil auch eine Funktion add() ?Ganz schwierig ist schon die Tatsache, dass ein tverw mehrere teile erzeugen soll .... wie soll das gehen ? Kann ein Opel auch mehrere Autos sein ?
Wenn ich die Aufgabe recht verstehe, soll außer tverw niemand ein teil erzeugen oder auf eine seiner Funktionen/Attribute zugreifen können.
Für eine "Zugriffsbeschränkung" bietet C++ "Access specifier" (public, protected, private) an.ich sehe immer noch zwei (IMO bessere) Entwurfsvarianten:
class tverw; // forward declaration class teil { // Alles private: Damit kann niemand außer friends was damit machen int meinPrivatesAttr; teil(int i) : meinPrivatesAttr(i) {} teil(teil const & other) { meinPrivatesAttr = other.meinPrivatesAttr; } teil const & operator=(teil const & other) { meinPrivatesAttr = other.meinPrivatesAttr; return *this; } ~teil() {} void meinePrivateFunc() const { cout << "ich bins: " << meinPrivatesAttr << "\n"; } friend tverw; }; class tverw { vector<teil> teile; int teilNummer; public: tverw() : teilNummer(0) {} void addTeil() { teile.push_back(teil(teilNummer++)); } void bearbeiteTeile() { vector<teil>::const_iterator it = teile.begin(); vector<teil>::const_iterator const end = teile.end(); for(; it != end; ++it) it->meinePrivateFunc(); } };(lustigerweise "weiß" tverw nicht mal, dass er der Einzige ist, der auf teil zugreifen kann - braucht er aber auch nicht; es reicht, dass es so ist)
Oder (wenn auch außerhalb von tverw niemand die Klasse teil sehen soll):
class tverw { class teil { // innere Klasse ... (wie oben) }; vector<teil> teile; int teilNummer; public: ... (wie oben) };In beiden Fällen erbt tverw NICHT von teil, sondern "aggregiert" sie.
Gruß,
Simon2.
-
Simon2 schrieb:
Glaube ich immer noch nicht.

macht nichts *g*
Simon2 schrieb:
(ich tippe mal drauf, dass da noch ein "erzeugt" kommen sollte)
im Prinzip ja... ich korrigiere: "[...] zu erzeugen."
Simon2 schrieb:
Nochmal die Frage: "IST tverw ein teil ?"
nein, 'tverw' verwaltet mehrere 'teil'e in einem Zeiger enthaltenden Array -->
teil * * tArr; [...] tArr = new teil * [tAnz];Simon2 schrieb:
Wenn also z.B. tverw von teil erbt ... hat dann teil auch eine Funktion add() ?
Hier bin ich mir in der Bedeutung der Vokabeln unsicher. Erbt ein 'friend'? 'teil' hat eine Funktion chgBestand() --> Bestand ändern.
Simon2 schrieb:
Ganz schwierig ist schon die Tatsache, dass ein tverw mehrere teile erzeugen soll .... wie soll das gehen ? Kann ein Opel auch mehrere Autos sein ?
Vielleicht muss man hier die Frage anders formulieren: "Passen in eine Garage mehrere unterschiedliche Autos?" Antwort: "Ja, wenn sie genug Stellplätze hat." Und da ich die Anzahl der benötigten 'Stellplätze' direkt vor dem Bau der Garage erfahre, baue ich sie groß genug. (Im Ernst: Die Anzahl der Datensätze geht aus der 4. Zeile der Datendatei hervor, direkt vor den dann folgenden unterschiedlichen Datensätzen.)
Simon2 schrieb:
Wenn ich die Aufgabe recht verstehe, soll außer tverw niemand ein teil erzeugen oder auf eine seiner Funktionen/Attribute zugreifen können.
Das verstehst du richtig.
Simon2 schrieb:
Für eine "Zugriffsbeschränkung" bietet C++ "Access specifier" (public, protected, private) an.
Das ist korrekt aber darum geht es leider nicht. Es geht darum, einer ziemlich konkreten Aufgabenstellung gerecht zu werden. Und die lässt wenig Spielraum. Wenn´s interessiert, dann stelle ich die Aufgabe mal zu Diskussion. Ach was, mach ich einfach: Download!
Deine Entwurfsvarianten kann ich leider mangels Kenntnissen nicht beurteilen. Ich werde versuchen sie bei Gelegenheit zu begreifen. Erzeugt[C++]vector<teil> teile;[/C++]nicht auch sowas wie eine 'Garage' für verschiedene 'teil'e?
Es fängt an, mir noch mehr Spaß zu machen!
so long
Christian
-
OK,
jetzt hast Du mich endgültig überzeugt ..... dass ich Recht habe.

- Ableiten: Wenn tverw ein teil ist
- Aggregieren: Wenn tverw einen/mehrere teil(e) verwaltet
(Wenn Du den Satz mal mit "tverw = Garage" und "teil = Auto" liest, wird die Wahl klar sein)
In Deinem Aufgabentext ist ja ein "Vererbungsschema" abgebildet - und da sieht man, dass tverw NICHT von teil erbt, sondern ein "teil-Array aggregiert" (teil** tArr).
Außerdem steht da zu teil:
"... abstrakte Basisklasse, da eine
rein-virtuelle Funktionen
deklariert ist, keine Instanz
möglich..."
D.h. Du brauchst gar nichts zu machen, damit teil nicht "von Außen" erzeugt werden kann ... das kann niemand ! Und zwar wegenvirtual void printTeil ( void ) = 0;ChrisPHL schrieb:
...
Simon2 schrieb:
Nochmal die Frage: "IST tverw ein teil ?"
nein, 'tverw' verwaltet mehrere 'teil'e in einem Zeiger enthaltenden Array -->
teil * * tArr; [...] tArr = new teil * [tAnz];OK, sorry, ich hatte "C++ gemacht", wo Euer Tutor offensichtlich noch "in C festklemmt".

Guter Stil wäre die Verwendung von std::vector (typsicher, komfortabel, unproblematisch bzgl. Speicherlecks/-überschreitungen) .... da solltest Du Deinen Tutor mal vorbeischicken, damit wir ihm hier die Ohren langziehen.
(Es kann natürlich sein, dass Ihr Speicherverwaltung lernen sollt, aber ich halte das heutzutage für Anfänger überflüssig, verwirrend und letztlich "Quatsch").Ihr sollt halt ein Array von Zeigern anlegen, wo ich einen vector von teilen verwendete .... mit den neuen Kenntnissen würde ich einen vector von Zeigern nehmen ( vector<teile*> - das nimmt Dir die Erweiterung von tArr und die Verwaltung der Anzahl in tAnz ab) .... aber anscheinend hast Du die Wahl nicht - macht aber nichts, es geht mit tArr&tAnz auch (musst nur ein wenig mehr frickeln).
ChrisPHL schrieb:
...
Simon2 schrieb:
Wenn also z.B. tverw von teil erbt ... hat dann teil auch eine Funktion add() ?
Hier bin ich mir in der Bedeutung der Vokabeln unsicher. Erbt ein 'friend'?
Zur Info: "Friend" kann jeder sein ... ob er nun in einer Vererbungsbeziehung steht oder nicht (z.B. können auch "freie Funktionen" befriended sein ... und die können natürlich nix erben. "friend" hat einfach mit "Vererbung" nichts zu tun.
OK, ich denke, Du kommst erstmal klar.
Wenn nicht, melde Dich wieder (bin aber wohl erst morgen abend wieder online - aber die anderen hier können das mindestens genauso gut).Gruß,
Simon2.
-
Du hast mir nochmal sehr geholfen! Tausend Dank!
Wenn du dir mal die "teile.cpp" aus der Aufgabenstellung anschaust, dann wird dir einiges klar... von wegen "[...] Tutor offensichtlich noch 'in C festklemmt'".
Habe soeben die Lösung fertig geschrieben.
Eine klitzekleine Frage dazu habe ich aber noch: Wenn ich mitcin = teilenummer;ganz bösartig einen Wert von z.B. 3456783468532784657893145 übertrage, verhaspelt sich... wer auch immer. Lese ich dagegen den Wert mit
scanf("%d", &teilenummer);ein, gibt´s das Teil halt nicht und fertig ist´s...
Warum, bzw: wie geht´s besser mit "cin" oder alg. im C++- Stil?Gruß
Christian
-
ChrisPHL schrieb:
...
cin = teilenummer;...
Falscher operator

cin >> teilenummer; if(!cin) { cout << "ungültige Eingabe\n"; return ... ; }Gruß,
Simon2.
-
Nein das löst es leider nicht...
Ich habe es mal mit einer solchen "Fangschaltung" probiert. Wenn ich bei einer "übergroßen" Eingabe dann einfach tatenlos die Funktion bende, dann kriegt man beim nächsten Aufruf der Funktion gleich eine alá "Falsche Eingabe!" übergebraten. Ein cin.sync(); führe ich vor dem "cin >> teilenummer;" (Jetzt stimmt der Operator aber! ;-)) aus.
Noch Ideen?Christian
-
Hmmm,
also bei mir klappt's:
int main() { int Nummer; cout << "Nummer eingeben; "; cin >> Nummer; if(!cin) { cout << "NOT cin\n"; } else { cout << "cin : " << Nummer << "\n"; } return 0; }Output:>>
Nummer eingeben; 12345678901234567890
NOT cin
<<Passt also - ich vermute, dass Du nach der Abfrage auf cin "falsch weitermachst".
Zum Einen musst Du natürlich teileNummer nochmal richtig einlesen - zum Anderen (und das hätte ich wohl gleich sagen sollen) musst Du vor der erneuten Verwendung von cin dessen Fehlerflag löschen mitcin.clear();Gruß,
Simon2.
-
Simon2 schrieb:
[...] und das hätte ich wohl gleich sagen sollen [...]
Genau!
cin.clear();Das fehlte noch, jetzt klappt´s!
Vielen Dank!
Christian
-
ChrisPHL schrieb:
Simon2 schrieb:
[...] und das hätte ich wohl gleich sagen sollen [...]
Genau!
cin.clear();Das fehlte noch, jetzt klappt´s!
Vielen Dank!
ChristianSchön !!!
Zum "fehlenden Hinweis": Ich ware davon ausgegangen, dass die Abfrage im main() stattfindet und im Fehlerfall das Programm abgebrochen wird .... soweit zu meiner Verteidigung.

Eine gute Nacht noch,
Simon2.
-
Simon2 schrieb:
[...] davon ausgegangen, dass die Abfrage im main() stattfindet [...]
Darfst du aber nicht! :p denn:
ChrisPHL schrieb:
Wenn du dir mal die "teile.cpp" aus der Aufgabenstellung anschaust, dann wird dir einiges klar... von wegen "[...] Tutor offensichtlich noch 'in C festklemmt'".
Na dann gute Nacht!
Gruß
Christian
-
ChrisPHL schrieb:
Simon2 schrieb:
[...] davon ausgegangen, dass die Abfrage im main() stattfindet [...]
Darfst du aber nicht! :p denn:
ChrisPHL schrieb:
Wenn du dir mal die "teile.cpp" aus der Aufgabenstellung anschaust, dann wird dir einiges klar... von wegen "[...] Tutor offensichtlich noch 'in C festklemmt'".
Na dann gute Nacht!
Gruß
ChristianSorry, dass ich Dir helfen wollte, ohne mir seitenweise fremden Source anzusehen - soll nicht wieder vorkommen. :p
Übrigens: Auf clear() kann man auch selbst kommen - dazu braucht man micht nicht.Gruß,
Simon2.
-
Ist doch kein Thema, hab nur kurz den Klugsch-beep-modus aktiviert.

Für das "clear()" bin ich glaube ich einfach noch zu sehr Anfänger Aber ich gelobe Besserung: Ab sofort komme ich selber auf das "clear()".Christian