Konstruktor Vererbung
-
Nexus schrieb:
...
Genau so hätt ichs auch gemacht, wollte gerade ansetzen, als ich gesehen habe, dass du bereits gepostet hast, aber ich wollte genau auf das selbe hinweisen. Seperate Funktionen und dann aufrufen derjenigen, die man braucht.
Selbst dem Engagement wollte ich so in etwa hinschreiben!
-
Um ehrlich zu sein, hatte ich ziemliche Angst, dass du in der Zwischenzeit genau das Gleiche schreibst. Gut, dass du erst etwas später begonnen hast!
-
Nexus schrieb:
Um ehrlich zu sein, hatte ich ziemliche Angst, dass du in der Zwischenzeit genau das Gleiche schreibst. Gut, dass du erst etwas später begonnen hast!
^^
Hattest Glück, weil ich gerade was anderes am lesen war.
-
Danke für das Lob
kenne das teilweise aus nem Matheforum da wird wild aneinander vorbei geredet.
Habe heute das erste Mal mit Vererbung was gemacht, aber von den Virtuellen Funktionen in der VL auch was gehört, von wegen erst zur Laufzeit bekannte Klassen etc. Ich denke ich brauche so etwas, wenn ichs richtig machen möchte, da du schreibst
Wichtig: Ich habe an dieser Stelle auf Laufzeitpolymorphie verzichtet, weil du mit diesem Konzept womöglich noch nicht vertraut bist. Wenn du allerdings Objekte von abgeleiteten Klassen als Basisklasse ansprechen willst (als Abstraktionsmöglichkeit), möchtest du vielleicht die für den jeweiligen Kontotyp spezifischen Informationen ausgeben. Dazu müsstest du die Methode konstostand_ausgeben() als virtual deklarieren. Auch an den virtuellen Destruktor sollte dann gedacht sein.
Ich möchte eine Klasse 2 fach vererben und auch in meiner Ausgabefunktion (die ich mittlerweile gesplittet habe ;)) den jeweiligen Kontotyp ausgeben. Ich könnte ja auch n String mit in den Konstruktor packen, in den ich schreibe, wie das Konto heißt? Aber gehts schöner?=)
Und ich habe gesehen, dass, wenn ich Referenzen bei Methoden für Strings benutze, dass die const sein müssen. Ist das, damit ich nicht eine längere Zeichenkette in den übergebenen Parameter schreibe? Aber auf der anderen Seite ist das doch wie ein Zeiger, da ist das doch egal, oder?
Auf jeden Fall gehts nur mit const. Ohne const läufts, wenn ich in meiner main() den Konstruktor mit String Parameter aus einer Variable aufrufe, was ich logisch finde, es ist eine Referenz auf den Speicherplatz der Variable. Könnte ich denn da den Inhalt verändern? Weil meine String Variable ist ja nicht konstant.Ui ähm ich hoffe das kann man verstehen.. im Grunde gehts hier drum:
main(){ string a="test"; funktion(a); funktion("test"); } funktion(string &a){ cout << a; a="veränderung" //das geht, wenns nicht "const string &a" ist.. // }
Und überhaupt benutzt ihr auch viel const in den Klassen:
class konto { protected: void inhaber_ausgeben() const; void saldo_ausgeben() const; ...
Ist das eine Vorsichtsmaßnahme?
So ich geh ins Bett, machts gut & schönen Dank :xmas2:
-
Ich gehe mal nur auf das 'const' ein:
Wenn du einen Parameter als 'string &' deklarierst, dann darfst du auch nur exakt den Typ 'string' als Referenz übergeben. Bei einem String-Literal "xyz" müßte erst ein temporäres string-Objekt erstellt werden (das würde dann aber vom Compiler wieder nach dem Aufruf gelöscht - und jegliche Änderung wäre verworfen) - und daher wird das vom Compiler nicht erlaubt.
Bei 'const string &' jedoch übergibst du ein konstantes Objekt, das in der Methode nicht verändert werden kann, und daher kannst du auch einfach "MeinKonto" übergeben, da du ja nur lesend auf diesen Parameter zugreifen kannst.Und die andere Verwendung des 'const' ist bei Methoden. Damit beschreibst du, daß diese Methode keine Änderung an dem Objekt(membern) vornimmt, d.h. daß es nur lesend auf Daten zugreift bzw. nur Ausgaben tätigt. Somit kannst du diese Methoden auch mit einem konstanten Objekt aufrufen:
const string s("Hello"); size_t len = s.length(); // length ist als 'const' deklariert s.append("World"); // <- Compilerfehler, da append das Objekt verändern würde
Such mal hier im Forum nach dem Begriff "const correctness" - dann findest du weitere Erklärungen (und auch das Schlüsselwort "mutable" (!), mit dem man die logische Konstantheit aufrecht erhalten kann).
Edit: schon zu lange kein C++ mehr programmiert...
-
Th69 schrieb:
(und auch das Schlüsselwort "mutual", mit dem man die logische Konstantheit aufrecht erhalten kann).
Das Keyword heißt nicht "mutual" sondern "mutable"
-
ups... setzen - sechs -)
-
Sooo besten Dank, das Programm ist fertig und läuft, aber ist wohl noch nicht ganz elegant. Aber es läuft
Allerdings drängt sich bei mir beim Betrachten von virtuellen Methoden folgendes Problem auf: "Virtual bedeutet im Grunde nichts anderes, als `redefinierbar'."
quelle:http://velociraptor.mni.fh-giessen.de/Programmierung/ProgII-htmldir/node9.html
Ich dachte, geerbte Methoden könne man immer redefinieren (ich setze das jetzt mal mit ändern gleich, darf ich das?)? Oder überlade ich geerbte Methoden nur?
Schöne Grüße & Danke im Voraus
-
Das spezielle an virtual ist, dass du auch wenn der dynamische Typ nicht bekannt ist seine Funktion aufrufen kannst (mit einem Zeiger auf die Basisklasse).
Wenn wir in C++ jetzt kein virtual hätten, könnte man mit einem Zeiger auf eine Basiklasse lediglich Funktionen der Basisklasse aufrufen und man hätte somit keine Polymorphie. (im Sinne von Laufzeitpolymorphie mit Vererbung).Also schau mal das hier an:
struct base { virtual void foo () { std::cout << "base foo";} void bar () { std::cout << "base bar"; } virtual ~base () {} }; struct a : base { void foo () { std::cout << "a foo"; } void bar () { std::cout << "a bar"; } }; int main () { base* b = new a; b->foo (); // gibt "a foo" aus b->bar (); // gibt "base bar" aus delete b; // dank dem virtuellen destruktor können wir auch das Objekt korrekt zerstören }
-
Krass, das ist mir noch nie aufgefallen bisher, aber hatte auch selten Methoden, die identisch hießen. Aber eigentlich bräuchte ich doch theoretisch dann die Funktionen garnicht in der Basisklasse zu definieren, wenn ich eh nicht vorhabe sie zu benutzen, aber es dient auch eher zur logischen Strukturierung, oder zur Benutzung, wenns komplizierter wird, korrekt?
Btw, ich schätze statt struct meinst du class oder?
Habe jetzt den Sinn verstanden denk ich. Das heißt also, ich habe 1 Basisklasse, und eine abgeleitete Klasse, in beiden eine quasi identische Methode definiert und kann immer nur die Methode der Basisklasse aufrufen?
Allerdings frage ich mich jetzt immer noch, ob die neue Methode die alte überlädt, oder richtig "neu schreibt", auch wenn das jetzt nicht mehr so wichtig ist
Dankeschön.. ihr seid genial=)
-
Ja, oftmals braucht man die Implementierung in der Basisklasse nicht, und dann macht man eine pure virtual function draus.
struct base { virtual void foo () = 0; // pure virtual function };
Es kann Sinn machen eine Basisimplementierung zu definieren, aber oft verwendet man so eine abstrakte Klasse. (siehe auch google abstract C++ class)
Und nein. Ich meine
struct
. struct ist das gleiche, wie class, ausser, dass die Funktionen standardmässigpublic
sind. (und auch standardmässigpublic
Vererbung).Nein. Das ist keine Überladung, sondern eine Neu Implementierung.
So, ich geh jetzt meine Geburtstag feiern.
-
Alles klar, besten Dank & viel Spaß