Frage zu Quellcode
-
Hallo zusammen,
ich habe eine Frage zu folgendem Quellcode:
#include <cstdlib> #include <iostream> using namespace std; class Mitarbeiter { protected: string nachname; string vorname; float gehalt; public: //1. FRAGE: //Warum ist die folende Zeile nicht erlaubt? //Mitarbeiter (string nn, string vn, float g): nachname(nn), vorname (vn), gehalt(g); Mitarbeiter(string nn, string vn, float g): nachname(nn), vorname (vn), gehalt(g){} void datenausgeben(){ cout << "Vorname: " << vorname << " Nachname: " << nachname << " Gehalt: " << gehalt <<endl; } }; class Angestellter : public Mitarbeiter { private: int urlaubsanspruch; public: Angestellter(string nn, string vn, float g, int u) : Mitarbeiter(nn, vn, g), urlaubsanspruch(u) {} //2. FRAGE: //Warum ist das hier nicht erlaubt? // Angestellter(string nn, string vn, float g, int u) : nachname(nn), vorname (vn), gehalt (g), urlaubsanspruch(u); //3.FRAGE //Ist das mit JAva- Vergleichbar (bei Java habe ich immer @override geschreiben??) void datenausgeben() { /4. Frage: //Ist der Aufruf der Methode der Superklasse so korrekt? Mitarbeiter::datenausgeben(); cout << "Urlaub " << urlaubsanspruch << endl; } }; int main(int argc, char *argv[]) { Angestellter huber ("Anton","Huber",20,30); huber.datenausgeben(); system("PAUSE"); return EXIT_SUCCESS; }Kann mir jemand bitte die Fragen beantworten?
Vielen Dank!!!
-
In C++ haste .h und .cpps
die .h's deklarieren (was gibts?) die .cpp's definieren (wie funktionierts?). Wenn du Konstruktor mit Initialisierungslisten nutzt, gehört das zum "wie funktionierts" ... daher brauchst du einen Methodenrumpf (in deinem Fall reicht
{}weil da sonst nix passiert (siehe: http://www.c-plusplus.net/forum/p434874#434874)Normalerweise so:
mitarbeiter.h
#include <string> // using namespace std; // niemals in Headern!! class Mitarbeiter { protected: std::string nachname; std::string vorname; float gehalt; public: Mitarbeiter(std::string, std::string, float); virtual void datenausgeben(); // wird von abgeleiteten Klassen überschrieben und dann deren Methode genutzt selbst bei pointern auf die Basisklasse };mitarbeiter.cpp
#include "mitarbeiter.h" #include <iostream> using namespace std; Mitarbeiter::Mitarbeiter(string nn, string vn, float g) : nachname(nn), vorname (vn), gehalt(g) { } void Mitarbeiter::datenausgeben() { cout << "Vorname: " << vorname << " Nachname: " << nachname << " Gehalt: " << gehalt <<endl; }angestellter.h
#include "mitarbeiter.h" #include <string> class Angestellter : public Mitarbeiter { // automatisch private int urlaubsanspruch; public: Angestellter(std::string, std::string, float, int); void datenausgeben(); };angestellter.cpp
#include "angesteller.h" #include <iostream> using namespace std; Angestellter::Angestellter(string nn, string vn, float g, int u) : Mitarbeiter(nn, vn, g), urlaubsanspruch(u) { } void Angestellter::datenausgeben() { Mitarbeiter::datenausgeben(); cout << "Urlaub " << urlaubsanspruch << endl; } };hab grad kein compiler zur Hand, Flüchtigkeitsfehler vorbehalten...
-
1. Du musst unterscheiden zwischen Deklaration und Definition von Funktionen (incl. Konstruktoren):
Mitarbeiter(string nn, string vn, float g);ist eine Funktionsdeklaration. Bei Deklarationen teilt man dem Compiler mit, dass es so eine Funktion gibt, welche Argumente sie hat und was sie "returnt".
Mitarbeiter(string nn, string vn, float g): nachname(nn), vorname (vn), gehalt(g){ ; }ist eine Definition. Es wird genau mitgeteilt, was passieren soll, wenn die Funktion aufgerufen wird (darum habe ich spaßeshalber ein ";" zwischen "{ }" eingefügt, weil Du dort auch Code reinschreiben kannst). Eine Initialisierungliste -das hinter dem Doppelpunkt- ist nur in der Definition erlaubt. Du gibt ja dort quasi schon Anweisungen, was passieren soll, wenn so ein Objekt angelegt wird. Das geht über die reine Deklaration hinaus.
2. s. 1.
3. kenne Java kaum.
4. richtig. Durch die Redefinition von datenausgeben() in der abgeleiteten Klasse ist der Eintrag der alten Funktion in er Funktionstabelle überschrieben. Um an die Funktion der Basisklasse aufzurufen musst Du das kenntlich machen mit Mitarbeiter::
-
1. + 2.: http://www.c-plusplus.net/forum/p1993089#1993089 zur genauen Erklärung von Header/Source.
3.: Lass mich raten... meinst du so etwas wie aus dem kommenden C++-Standard? http://en.wikipedia.org/wiki/C%2B%2B0x#Explicit_virtual_function_overrides
-
Hallo,
mit Override habe ich so etwas gemeint:
Mit diesem Typ kann eine Methode gekennzeichnet werden, die die Methode ihrer Oberklasse überschreibt. Der Compiler stellt dann sicher, dass die Oberklasse diese Methode enthält und gibt einen Fehler aus, wenn dies nicht der Fall ist. Beispiel: public class A { public void eineMethode() {} } public class B extends A { @Override public void eineMethode() {} }Ich habe noch eine Frage:
#include <cstdlib> #include <iostream> using namespace std; class Mitarbeiter { protected: string nachname; string vorname; float gehalt; public: //WARUM WIRD DER STANDARDKONSTRUKTOR NOCH EXTRA BENÖTIGT?? Mitarbeiter () { } Mitarbeiter(string nn, string vn, float g): nachname(nn), vorname (vn), gehalt(g){} void datenausgeben(){ cout << "Vorname: " << vorname << " Nachname: " << nachname << " Gehalt: " << gehalt <<endl; } }; class Angestellter : public Mitarbeiter { private: int urlaubsanspruch; public: Angestellter(string nn, string vn, float g, int u) : urlaubsanspruch(u) { nachname = nn; vorname = vn; gehalt = g; } void datenausgeben() { Mitarbeiter::datenausgeben(); cout << "Urlaub " << urlaubsanspruch << endl; } }; int main(int argc, char *argv[]) { Angestellter huber ("Anton","Huber",20,30); huber.datenausgeben(); system("PAUSE"); return EXIT_SUCCESS; }Wenn ich die Werte im Konstruktor der Klasse Angestellter setzen möchte, dann muss ich den Standardkonstruktor von Mitarbeiter definieren.
Wisst ihr warum das so ist?
Ich dacht der Standardkonstruktor ist automatisch vorhanden?
Vielen Dank!
Viele Grüße
-
#include <cstdlib> #include <iostream> using namespace std; class Mitarbeiter { protected: string nachname; string vorname; float gehalt; public: //WARUM WIRD DER STANDARDKONSTRUKTOR NOCH EXTRA BENÖTIGT?? // Mitarbeiter () {} // WIRD ER NICHT WENN MANS RICHTIG MACHT!!!!! Mitarbeiter(string nn, string vn, float g): nachname(nn), vorname (vn), gehalt(g){} virtual // DAMIT WIRD SIGNALISIERT DAS DAS VON ABGELEITETEN KLASSEN ÜBERSCHRIEBEN WIRD, SONST "VERDECKST" DU NUR void datenausgeben() { cout << "Vorname: " << vorname << " Nachname: " << nachname << " Gehalt: " << gehalt <<endl; } }; class Angestellter : public Mitarbeiter { private: int urlaubsanspruch; public: /* SO FALSCH Angestellter(string nn, string vn, float g, int u) : urlaubsanspruch(u) { nachname = nn; vorname = vn; gehalt = g; } */ Angestellter(string nn, string vn, float g, int u) : Mitarbeiter(nn,vn,u), urlaubsanspruch(u) {} // BASISKLASSENKONSTRUKTOR AUFRUFEN, DU MACHST DAS NICHT DAHER BRAUCHST // DU NOCH DEN () KONSTRUKTOR ZUM KONSTRUIEREN DER LEEREN BASISKLASSE } void datenausgeben() { Mitarbeiter::datenausgeben(); cout << "Urlaub " << urlaubsanspruch << endl; } };Spass (und Geschreie) beiseite, das mit dem virual wird dann wichtig wenn du sowas machst
Mitarbeiter * mit = new Angestellter("a","b", 1.2, 344); mit->datenausgeben();Wenn du das nicht als viruell deklarierst nimmt der hier die Datenausgabe von Mitarbeiter und unterschlägt die Urlaubstage, als virtuell deklariert wird erst aufgelöst welche Klasse das wirklich ist und dann die überladene Methode genommen. Wenn du nur verdeckst (die selbe Methode nochmal in der Kindklasse implementierst findet diese Auflösung NICHT statt und er nimmt auch die von Mitarbeiter. Achso und wenn du GANZ GENAU HINSCHAUST siehst du das ich das mit dem virutal bereits in der ersten Antwort schrieb ... aber so ein keyword ist leicht übersehen. Und zum Thema "Konstruktor ist automatisch da ... " das gilt nur wenn du KEINEN Konstruktor schreibst, dann musst du das selbst machen. Es ginge in deinem Fall auch einfach so:
Mitarbeiter(string nn="", string vn="", float g=0.0): nachname(nn), vorname (vn), gehalt(g){}dann wird im Fall von
Mitarbeiter gaertner;dieser mit namen "", vornamen "" und Gehalt 0.0 angelegt
-
Wie gesagt, sicherstellen, dass etwas überschrieben wird, kannst du nur in C++0x...
-
Danke für die Antworten!
Virtual hatten wir bis jetzt noch nicht in der Vorlesung.
Ist das dann generell so: Sobald ich selbst einen Konstruktor erzeuge, dann existiert der Standardkonstruktor nicht mehr, sondern muss ihn noch mal explizit selbst erstellen??
Viele Grüße
-
Role schrieb:
Sobald ich selbst einen Konstruktor erzeuge, dann existiert der Standardkonstruktor nicht mehr, sondern muss ihn noch mal explizit selbst erstellen??
richtig

-
Schau dir mal die Dreierregel an!
-Kopierkonstruktor
-Konstruktor/Destruktor
-ZuweisungsoperatorAlles Sachen die ohne zu Fragen erstellt werden.