Merfachvererbung
-
Dein Modell sagt, dass dein InCall/OutCall Klassen Telefonnummern sind. Das ist das Gleiche als wenn ich sage ein Auto ist ein Motor. Das ist einfach falsch modelliert. Genauso könntest du eine Person so modellieren:
class Person : public Vorname, public Nachname, public Geburtsdatum { }
Es ist einfach Quatsch, und wenn du dabei bleiben möchtest: Weiterhin viel Erfolg!
-
@C-Sepp sagte in Merfachvererbung:
Ein Incall/Outcall ist natürlich keine Telefonnummer weil es ja zwei Klassen sind.
Eine Vererbung ist eine aber "Ist eine Beziehung". Ein BMW i3 ist ein Auto. Aber ein Anruf ist kein ausgehender und eingehender Anruf.
Ein Telefonanruf besteht aber aus mehreren Teilnehmern, einem Typ (Telefon, Video), der Anrufdauer, usw. Jeder Telefonteilnehmer hat eine Telefonnummer, potenzielle Anrufzeiten, usw.
Und wo immer du bestehst hörst, ist Aggregation ("besteht aus Beziehung") die erste Wahl.
-
@C-Sepp sagte in Merfachvererbung:
pnr.getphonenr()
Was soll hier die Funktion zurückliefern? Die Telefonnummer der eingehenden Nummer oder der ausgehenden?
-
@DocShoe sagte in Merfachvererbung:
Es ist einfach Quatsch, und wenn du dabei bleiben möchtest: Weiterhin viel Erfolg!
Ich stimme zu, dass das so wie es hier implemetiert wurde "Quatsch" ist und man damit sehr schnell in Teufelsküche kommt. Besonders als Anfänger.
Allerdings sehe ich das mit der "ist-ein"-Beziehung" generell nicht ganz so dogmatisch. So ein Pattern kann manchmal sinnvoll sein und helfen, redundanten Code einzusparen. Immerhin gibt es in der OOP auch ein Konzept, das man als "Mixin" bezeichnet. Das würde ich aber nur sehr sparsam einsetzen und derart, dass es nicht zu solchen Konflikten kommt. C++ kennt eben nur Mehrfachvererbung und keine speziellen Sprachkonstrukte für Mixins, mit denen man das weniger fehleranfällig hinbekommt.
@C-Sepp du wärst hier m.E. tatsächlich besser beraten, z.B. die Telefonnummern zu Membern von
InCall
/OutCall
zu machen und bei diesen auch die "Ist-ein"-Beziehung zu berücksichtigen.InCall
ist einPhoneCall
, alsoInCall : public PhoneCall
ist denke ich ein besserer Ansatz für eine saubere Codestruktur die einem nicht so früh bereits um die Ohren fliegt
-
Dieser Beitrag wurde gelöscht!
-
@Schlangenmensch sagte in Merfachvererbung:
Abgesehen davon, das @DocShoe recht hat und man das wohl bessser nicht durch eine Vererbungsstruktur abbildet, gäbe es Virtual Inheritance, was solche Probleme löst:
class InCall : virtual public PhoneNr class OutCall : virtual public PhoneNr
Virtual inheritance wäre hier nun wirklich total verkehrt. Das ganze über Vererbung zu modellieren ist Quatsch, das ist klar. Aber wenn man es aus irgend einem Grund trotzdem unbedingt tun will, dann braucht man hier ganz klar zwei getrennte
PhoneNr
Sub-Objekte. Weil halt die eingehende Telefonnummer selten gleich der ausgehenden Telefonnummer ist.
-
@hustbaer Ja, da gebe ich dir Recht.
Ich bin irgendwie davon ausgegangen, dass es primär darum ging sich mit Mehrfachvererbung in C++ auseinander zu setzen und das dafür ein eher unpassendes Beispiel drum herum konstruiert wurde. Daher ging es mir darum das Sprachfeature der Virtuellen Vererbung als Lösung des Dread Diamond Problems anzubringen.
-
@C-Sepp Was man machen könnte: man könnte private Vererbung einsetzen. Aber, ich glaube, ich habe das tatsächlich noch nie benutzt:
#include <iostream> using namespace std; class PhoneNr { private: string phonenr; public: PhoneNr(string phnr = "0") : phonenr(phnr) {} string getphonenr() const { return phonenr; } void setphonenr(string phnr) { phonenr = phnr; } }; class InCall : public PhoneNr { bool phcrecorded; public: InCall(const string& inNr) : PhoneNr(inNr), phcrecorded(false) {} bool getflag() const { return phcrecorded; } void setflag(bool phcrc) { phcrecorded = phcrc; } }; class OutCall : public PhoneNr { bool cncestablished; public: OutCall(const string& outNr) : PhoneNr(outNr), cncestablished(false) {} bool getflag() const { return cncestablished; } void setflag(bool cncest) { cncestablished = cncest; } }; class PhoneCall : InCall, OutCall { public: PhoneCall(const string& inNr, const string& outNr) : InCall(inNr), OutCall(outNr){} void printNrs() const { cout << "in nr: " << InCall::getphonenr() << "\n"; cout << "out nr: " << OutCall::getphonenr() << "\n"; } }; int main() { const PhoneCall phc ("in number", "out number"); phc.printNrs(); return 0; }
Abgesehen, dass die Modellierung zwischen
Call
undPhoneNr
nicht stimmt, könnte man anstatt von privater Vererbung auch gleich Member Variablen einsetzen. Das ist halt mehr oder weniger für den Fall, dass das eine Übungsaufgabe irgendeines Lehrers ist, der auf Vererbung besteht.Außerdem, Parameterlose Funktionen brauchen in C++ kein
void
als "Parameter".Aber, wenn es freigestellt ist, wie du das ganze löst, würde ich über ein Redesign nachdenken. Ein Anruf hat mindestens 2 Teilnehmer (können aber auch mehr sein, oder). Jeder Teilnehmer hat eine Telefonnummer. Ein Anruf kann eventuell aufgezeichnet werden (aber, dass nur eine Seite aufgezeichnet wird, wäre zumindest mir unbekannt).
-
@hustbaer sagte in Merfachvererbung:
...
Weil halt die eingehende Telefonnummer selten gleich der ausgehenden Telefonnummer ist.
...Vielleicht kann man die hier als EndPoint sehen, da sie zum Hören der
InCall
ist und zum Sprechen derOutCall
. Allerdings werden für ein vollständiges Call-Objekt die gleichen Informationen für die Gegenstelle benötigt.
-
Vielen dank für die Ratschläge. Dann weis ich auch gleich wie die Übungsaufgabe eigentlich abgewandelt werden sollte.
In einer weiteren Aufgabe dazu geht es darum die Funktion dial() zu schreiben:
"Dial() erhält als Argument eine anzurufende Telefonnummer. Falls die Sitzung initialisiert wurde und die Nummer des angerufenen Telefonanschlusses "0" ist, setzt die Methode das Flag zum Verbindungsaufbau auf true"
Die Lösung dazu sieht folgendermaßen aus:bool PhoneCall::dial(const string& n) { if (InCall::getphonenr()=="0" && OutCall::getphonenr() !="0") { InCall::setphonenr(n); OutCall::setflag(true); return true; } else return false; }
Warum kann in dem Fall der Wert von phonenr über zwei Funktionen getphonenr() in der Klasse InCall und
OutCall abgefragt werden? Sicherlich gibt es ja zwei Version von getphonenr() in beiden Klassen aufgrund
der Vererbungshierarchie, trotzdem greifen doch beide Versionen auf das selbe Datenelement phonenr
zu, oder wie kann man sich das im Speicher vorstellen? Danke!
-
@C-Sepp Wenn das eine Übungsaufgabe ist, zu der du eine Musterlösung hast, wäre es hilfreich, wenn du die zusammen postest. Woher sollen wir denn so wissen, wie da tatsächlich die Vererbungshierarchie aussieht und was laut Aufgabe gefordert wurde?
Wenn das mittels privater Vererbung gelöst wurde, könnte das so funktionieren, bei virtueller Vererbung nicht.
Wie gesagt, poste den gesamten Code, sonst ist das alles nur geraten
-
@C-Sepp
Ist das zufällig ein C++ "Buch" von Jürgen Wolf?
-
@DocShoe sagte in Merfachvererbung:
Ist das zufällig ein C++ "Buch" von Jürgen Wolf?
Da könnte man auch fragen "Hast du dir einen Wolf programmiert?"
SCNR
-
Ne zum Glück nicht. Moment...ich poste mal die komplette Aufgabenstellung dazu
-
Die Software einer Telekommunikationsgesellschaft soll Telefonverbindungen erfassen. Es sind die Telefonnummern von Anrufern und Empfängern sowie der Auf- und Abbau von Verbindungen zu simulieren.
Definieren Sie zu dem Zweck eine Basisklasse PhoneNr zur Darstellung einer Telefonnummer, die nur ein Datenelement vom Typ string besitzt. Es gibt nur einen Dafault-Konstruktor, der die Telefonnummer auf "0" setzt, sowie Zugriffsmethoden, die die Telefonnummer setzen bzw. lesen.
Die Klassen InCall und OutCall entstehen aus PhoneNr durch public Vererbung. OutCall besitzt ein zusätzliches boolsches Flag flag, das anzeigt, dass eine Telefonverbindung aufgebaut wird. InCall besitzt ein zusätzliches Flag flag, das anzeigt, dass ein Telefonanruf angenommen wurde, dass heißt dass eine Verbindung besteht. Beide Klassen besitzt einen Default-Konstruktor, der das jeweilige Flag false setzt und Zugriffsmethoden getflag() und setflag() zum Lesen bzw. Schreiben des jeweiligen Flags.
Die Klasse PhoneCall entsteht aus InCall und OutCall durch public-Vererbung. Sie besitzt kein zusätzliches Datenelement und folgende Methoden:
1.InitCall() setzt die als Argument übergebene Telefonnummer eines Anrufers, falls seine gespeicherte Nummer "0" ist, und initialisiert so eine Sitzung.
2. dial().....so wie bereits beschriebenDie Lösung dazu unterscheidet sich nicht zu meinen Code, den ich gestern gepostet habe. Nur die Funktion dial() muss wiegesagt neugeschrieben werden.
-
Uff
Haste nen Link zur Aufgabe? Oder den Namen des Buches?
-
wozu noch der Link...das ist doch schon die komplette Aufgabe
-
Nen Link habe ich leider nicht
-
@C-Sepp sagte in Merfachvererbung:
wozu noch der Link...das ist doch schon die komplette Aufgabe
Würde ganz gerne sehen, welche Aufgaben da sonst noch so gestellt werden.
Wie heisst denn das Buch oder wasauchimmer?
-
Krasses Versagen des Buches, ich würde das nämlich einen solch groben Modellierungsfehler nicht so entspannt sehen wie manch andere hier. Das ist schon ein Wegwerfgrund. Ganz ernst, ohne Überteibung, denn wer solchen Müll an einer Stelle schreibt, der macht das auch an anderen Stellen. @C-Sepp: Du merkst ja vielleicht auch selber, dass du hier eher "dumme" Fragen stellen musst. Das ist nicht normal für Anfänger auf deinem Niveau. Das liegt an dem schlechten Lehrmaterial. Daraus wirst du nur schlechtes C++ lernen, und das wieder zu verlernen ist hinterher viel schwieriger, als es gleich richtig zu lernen. Und neu lernen musst du später sowieso.