Konstruktor und Virtuelle Methoden
-
Dima schrieb:
1. Wieso wird unbedingt der Default Konstruktor in der Klasse Dreieck benötigt?
Bei weglassen gibt es compilerfehler.1. Weil "gleichseitigesDreieck" keinen anderen in der Initialisierungsliste aufruft.
gleichseitigesDreieck(float seite) : Dreieck(xxx, yyy), // <-- xxx,yyy entsprechend austauschen a(seite) {}2. Man schreibt man auch den Fehler dazu, die funktionierenden Glaskugeln sind leider Mangelware.
3. gleichseitigesDreieck ist eh ein Designfehler. es währe besser der Klasse Dreieck eine Methode alle isGleichseitig zu verpassen. Den nach dem Design ist ein gleichseitigesDreieck zwar ein Dreieck, aber ein Dreieck niemals gleichseitig.Dima schrieb:
Die Klasse Figur ist eine Abstrakte Klasse mit den beiden Virtuellen Methoden Flaeche() und Daten(), macht es Sinn die beiden Methoden in der Basisklasse Dreieck auch virtuell anzulegen? Wenn ja welche Vor/Nachteile hat man dann davon.
Es macht keinen Unterschied da "virtual" quasi mitvererbt wird.
cu André
-
Ok, habe vergessen zu erläutern, dass das Problem in der folgenden Zeile liegt.
Es spielt im Moment keine Rolle, wie die klasse verwendet wird.gleichseitigesDreieck(float seite) : a(seite) {}ich möchte bloß, dass in der klasse Dreieck das Objekt mit zwei variablen instantiiert wird und in der klasse gleichseitigesDreieck nur mit einer Variable.
Beim weglassen des Standardkonstruktors in der basisklasse bringt mir der compiler einen fehler, dass er den zugehörigen konstruktor in der Basisklasse nicht findet.
Ich muss entweder den Standardkonstruktor oder ich einen neuen anlegen, der mir die variablen der Basisklasse benutzt:Dreieck(float grundseite) : g(grundseite) {}Dann habe ich das Problem, dass beim erstellen von Objekten der Klasse Dreieck so etwas zulässig ist:
[cpp]
Dreieck dreieck1(); //soll nicht sein
Dreieck dreieck2(1); //soll auch nicht sein
gleichseitigesDreieck dreieck3(2); //ok
Dreieck dreieck4(2,3); //okMfG
Dima
-
Warum machst dus dann nicht einfach so wie ich dir das gezeigt habe?
-
Braunstein schrieb:
Warum machst dus dann nicht einfach so wie ich dir das gezeigt habe?
Sorry, habe ein wenig länger gebraucht um den Beitrag zu Verfassen. Danke für euere unterstützung.
Bin nicht so flink mit den Fingern.
d.h. Nur fürs verständnis. Man braucht, wenn Variablen in der unterklasse initialisiert werden, einen passenden kostruktor in der Basisklasse???
2. Habt ihr etwas mehr info material Links,etc. für das stichwort virtuell? raff es einfach nicht.

-
Das ist komisch formuliert und trifft es irgendwie immer. Natürlich braucht die Basisklasse den Konstruktor, den Du in der Unterklasse aufrufst. Der springende Punkt ist, du musst im Konstruktor jeder abgeleiteten Klasse (irgend)einen Konstruktor der Basisklasse explizit aufrufen, wenn die Basisklasse keinen Default-Konstruktor (den ohne Parameter) hat.
-
zu virtual
http://tutorial.schornboeck.net/virtual.htm
http://www.ica1.uni-stuttgart.de/Courses_and_Lectures/C++/script/node18.html#SECTION00422000000000000000
-
LordJaxom schrieb:
Das ist komisch formuliert und trifft es irgendwie immer. Natürlich braucht die Basisklasse den Konstruktor, den Du in der Unterklasse aufrufst.Der springende Punkt ist, du musst im Konstruktor jeder abgeleiteten Klasse (irgend)einen Konstruktor der Basisklasse explizit aufrufen, wenn die Basisklasse keinen Default-Konstruktor (den ohne Parameter) hat.
Jetzt fehlt mir zum verständnis das warum?. Wieso muss ich den explizit einen konstruktor in der Basisklasse aufrufen? Ich habe ja einen Konstruktor in der abgeleiteten Klasse erstellt und möchte nur die Variablen der abgeleiteten klasse initialisieren. Um die Vererbten Variablen zu initialisieren würde es mir einleuchten, dass man den konstruktor der Basisklasse benötigt, aber warum auch für die Variableninitialisierung nur in der abgeleiteten klasse?

Braunstein schrieb:
zu virtual
http://tutorial.schornboeck.net/virtual.htm
http://www.ica1.uni-stuttgart.de/Courses_and_Lectures/C++/script/node18.html#SECTION00422000000000000000Danke für die links werde sie mir gleich duch den Schädel ziehen.

-
Dima schrieb:
Jetzt fehlt mir zum verständnis das warum?. Wieso muss ich den explizit einen konstruktor in der Basisklasse aufrufen? Ich habe ja einen Konstruktor in der abgeleiteten Klasse erstellt und möchte nur die Variablen der abgeleiteten klasse initialisieren. Um die Vererbten Variablen zu initialisieren würde es mir einleuchten, dass man den konstruktor der Basisklasse benötigt, aber warum auch für die Variableninitialisierung nur in der abgeleiteten klasse?

Die Basisklasse ist doch immer Teil der abgeleiteten, so musst Du den Basisklassenanteil auch immer konstruieren (lassen). Und das macht nunmal der Konstruktor der Basisklasse. Du kommst in der abgeleiteten ja auch garnicht an die private-Member der Basisklasse ran.
-
LordJaxom schrieb:
Die Basisklasse ist doch immer Teil der abgeleiteten, so musst Du den Basisklassenanteil auch immer konstruieren (lassen). Und das macht nunmal der Konstruktor der Basisklasse.
Das ergibt Sinn. Danke.
LordJaxom schrieb:
Du kommst in der abgeleiteten ja auch garnicht an die private-Member der Basisklasse ran.
Ja schon, aber an die protected.
MfG
Dima
-
Dima schrieb:
Jetzt fehlt mir zum verständnis das warum?. Wieso muss ich den explizit einen konstruktor in der Basisklasse aufrufen? Ich habe ja einen Konstruktor in der abgeleiteten Klasse erstellt und möchte nur die Variablen der abgeleiteten klasse initialisieren. Um die Vererbten Variablen zu initialisieren würde es mir einleuchten, dass man den konstruktor der Basisklasse benötigt, aber warum auch für die Variableninitialisierung nur in der abgeleiteten klasse?
Weil ein Konstruktor immer alle nichtstatischen Member (und dazu zählen mögliche Basisklasse) initialisiert, wenn diese keine PODs sind. PODs werden nur initialisiert, wenn sie explizit in der Initialisierungsliste auftauchen.
Deine Verwirrung ist nicht ganz unberechtigt, allerdings liegt das Problem an anderer Stelle. Ein (Objekt des Typs) gleichseitigesDreieck ist kein Dreieck. Generell (99:1) ist es ein Fehler, von konkreten Klassen (solche, die selbst vollständige Objekte erstellen) öffentlich abzuleiten.
-
asc schrieb:
gleichseitigesDreieck(float seite) : Dreieck(xxx, yyy), // <-- xxx,yyy entsprechend austauschen a(seite) {}Das sieht irgenwie getrickst aus. Gibt es keine andere möglichkeit?
Den das Dreieck(x, y) benötig man ja gar net. Denn die Variablen von Dreieck will ich nicht benutzen.
-
Da sind sie deswegen trotzdem. Genau sowas verrät dir meist einen Designfehler.
Du könntest gleichseitigesDreieck ja auch von Figur ableiten. Dann hast du das Problem nicht.
-
Gegenwärtig hast du:
Figur | Dreieck | gleichseitigesDreieckbesser ist:
Figur | AbstractDreieck / \ Dreieck gleichseitigesDreieckAbstractDreieck stellt dabei nur das gemeinsame Interface dar.
-
camper schrieb:
Weil ein Konstruktor immer alle nichtstatischen Member (und dazu zählen mögliche Basisklasse) initialisiert, wenn diese keine PODs sind. PODs werden nur initialisiert, wenn sie explizit in der Initialisierungsliste auftauchen.
Deine Verwirrung ist nicht ganz unberechtigt, allerdings liegt das Problem an anderer Stelle. Ein (Objekt des Typs) gleichseitigesDreieck ist kein Dreieck. Generell (99:1) ist es ein Fehler, von konkreten Klassen (solche, die selbst vollständige Objekte erstellen) öffentlich abzuleiten.
Ja ein design fehler ist es alle mal, aber die Aufgabenstellung verlangt es nunmal das man von einem Rechteck ein Quadrat ableiten soll. Oder von Dreieck einen Gleichseitigen und Gleichschenkligen ableiten müsse. Deswegen kommen mir auch solche Fragen hoch. Aber immer positiv sehen aus fehlern anderer lern man auch.

-
camper schrieb:
Weil ein Konstruktor immer alle nichtstatischen Member (und dazu zählen mögliche Basisklasse) initialisiert, wenn diese keine PODs sind. PODs werden nur initialisiert, wenn sie explizit in der Initialisierungsliste auftauchen.
Sorry POD ???
-
camper schrieb:
...PODs werden nur initialisiert, wenn sie explizit in der Initialisierungsliste auftauchen....

Echt ?struct A { int a, b; A() : a(1), b(2) {} }; struct B : A { }; int main() { B b;Wird hier nicht A::A() aufgerufen ?
Oder ist A kein POD ?Gruß,
Simon2.
-
Du wartest jetzt zwar sicher auf camper,
aber:
Eine struct mit Konstruktor ist kein POD mehr
@Dima
POD (Plain old data).
-
Dima schrieb:
Das sieht irgenwie getrickst aus. Gibt es keine andere möglichkeit?
Den das Dreieck(x, y) benötig man ja gar net. Denn die Variablen von Dreieck will ich nicht benutzen.Du hast hierbei ein Deckproblem, hierzu rollen wir mal alles auf (Nur bezogen auf den Regelfall, nicht auf solche Spezialitäten wir private Ableitungen...):
Ja, umgangssprachlich kann man sagen das ein gleichseitigesDreieck ein Dreieck ist. Vererbung setzt man ein um Anzuzeigen, das es sich um ein spezialisiertere Form handelt, nicht aber für Einschränkungen. Alles was die Basisklasse als Schnittstelle unterstützt muss auch die abgeleitete Klasse unterstüzen. Die abgeleitete Klasse "ist ein" auch ein Element der Basisklasse.
Einschränkungen stellt man besser durch Eigenschaften dar, als durch Ableitungen. Ich schätze mal du wirst es an einen extremen Beispiel verstehen:
class Dreieck; class BlauesDreieck : public Dreieck;Ich hoffe mal dir leuchtet ein, das sowas nicht sinnvoll ist.
So, da eine Abgeleitete Klasse nun alles was die Basisklassen repräsentieren auch darstellt, muss es auch alles initialisieren was dazu gehört. Dazu müssen passende Konstruktoren der Basisklasse aufgerufen werden. Falls es kein Standardkonstruktor gibt, musst du einen spezialisierten in der Initialisieungsliste aufrufen.
Was aber grundsätzlich geht: Du kannst einen Konstruktor auch protected deklarieren, so das er von Außerhalb nicht zugreifbar ist. Aber auch das verbessert kein schlechtes Design.
Und zu guter letzt: Vererbung lässt sich auch durch Komposition ersetzen. Bei Komposition enthält deine Klasse eine andere, gibt aber nur seine Schnittstelle frei. Du könntest z.B. sagen du schreibst eine Klasse gleichseitigesDreieck, da aber die Regeln für ein Dreieck nicht vollständig zutreffen leitest du nicht ab, sondern schreibst eine passende Schnittstelle. Bei der Implementierung kannst du aber auf das Dreieck zurückgreifen, und nimmst daher ein Dreieck als Member.
Noch immer kein wirklich gutes Design, aber besser als die Vererbung.
cu André
-
Dima schrieb:
Ja ein design fehler ist es alle mal, aber die Aufgabenstellung verlangt es nunmal das man von einem Rechteck ein Quadrat ableiten soll. Oder von Dreieck einen Gleichseitigen und Gleichschenkligen ableiten müsse. Deswegen kommen mir auch solche Fragen hoch. Aber immer positiv sehen aus fehlern anderer lern man auch.

Vermutlich kommt die "Auflösung" nach der Aufgabenstellung, mit einer Erklärung warum es schlechtes Design ist ;p
-
asc schrieb:
Ableitungen. Ich schätze mal du wirst es an einen extremen Beispiel verstehen:
class Dreieck; class BlauesDreieck : public Dreieck;Ich hoffe mal dir leuchtet ein, das sowas nicht sinnvoll ist.
Nee, das leutet mir jetzt nicht ein.
Ein BlauesDreieck kann ja im prinzip alles von der Basisklasse erben immerhin ist es ja ein dreieck, bloß das es blau ist. Also eine Eigenschaft z.B. Farbe mehr hat. also könnte man doch die Eigenschaften und Methoden von dem Dreieck erben? Oder nicht?Und zu guter letzt: Vererbung lässt sich auch durch Komposition ersetzen. Bei Komposition enthält deine Klasse eine andere, gibt aber nur seine Schnittstelle frei. Du könntest z.B. sagen du schreibst eine Klasse gleichseitigesDreieck, da aber die Regeln für ein Dreieck nicht vollständig zutreffen leitest du nicht ab, sondern schreibst eine passende Schnittstelle. Bei der Implementierung kannst du aber auf das Dreieck zurückgreifen, und nimmst daher ein Dreieck als Member.
Noch immer kein wirklich gutes Design, aber besser als die Vererbung.
[/quote]
Wie sieht den so eine komposition aus?
evtl. C++ Code? Bin eher praktisch orientiert