Destruktor problem cpp
-
Hallo erst mal,
ich sitze gerade an einer Hausarbeit/Laboraufgabe und ich habe irgendwo einen Fehler eingebaut und ich kann diesen nicht finden.
Erst mal zur Aufgabe:Schreiben Sie eine Klasse 'Student' mit den Attributen '_name' und '_first_name' vom Typ String. Schützen Sie die Attribute gegen Zugriff von außen. Die folgenden Methoden implementieren sie außerhalb der Klasse: Die Klasse soll einen parametrisierten Konstruktor haben, der Name und Vorname entgegennimmt und die beiden Attribute '_name' und '_first_name' entsprechend belegt. Verwenden Sie hierzu keine Initialisierungsliste. Schreiben sie get-Methoden für beide Attribute und einen Destruktor. Schreiben Sie zwei print-Methoden, beide ohne Rückgabewert. Eine der beiden Methoden nimmt eine boolsche Variable entgegen, mit der gesteuert werden kann, ob am Ende der Zeile ein Zeilenumbruch erfolgen soll oder nicht. In der anderen Methode erfolgt immer ein Zeilenumbruch.
Für die Klasse Employee soll ich genau die gleichen Methoden implementieren nur halt innerhalb der Klasse und mit einer Initialisierungsliste.
Ich habe nun das Problem das irgendwie ein Destruktor aufgerufen wird, wo es gar kein Sinn ergibt.
Einmal die gewollte Ausgabe:
Parametrisierter Konstruktor Student: Max Mustermann
Konvertierungskonstruktor Employee: Max Mustermann
Parametrisierter Konstruktor Employee: Erika Mustermann
Standardkonstruktor Employee: Erika Mustermann
print() ohne Parameter; Student: Max Mustermann
print() mit Parameter; Student: Max Mustermann
print() ohne Parameter; Mitarbeiter: Max Mustermann
print() ohne Parameter; Mitarbeiter: Erika Mustermann
Block wird betreten
Parametrisierter Konstruktor Student: Markus Mustermann
print() mit Parameter; Student: Markus Mustermann
Block wurde verlassen
Destruktor Student: Markus Mustermann
Destruktor Employee: Erika Mustermann
Destruktor Employee: Max Mustermann
Destruktor Student: Max MustermannUnd einmal meine Ausgabe:
Parametrisierter Konstruktor Student: Max Mustermann
Konvertierungskonstruktor Employee: Max Mustermann
Destruktor Student: Max Mustermann <----- Hier liegt das problem
Parametrisierter Konstruktor Employee: Erika Mustermann
Standardkonstruktor Employee: Erika Mustermann
print() ohne Parameter; Student: Max Mustermann
print() mit Parameter; Student: Max Mustermann
print() ohne Parameter; Mitarbeiter: Max Mustermann
print() ohne Parameter; Mitarbeiter: Erika Mustermann
Block wird betreten
Parametrisierter Konstruktor Student: Markus Mustermann
print() mit Parameter; Student: Markus Mustermann
Block wurde verlassen
Destruktor Student: Markus Mustermann
Destruktor Employee: Erika Mustermann
Destruktor Employee: Max Mustermann
Destruktor Student: Max Mustermann#include <string> #include <iostream> using namespace std; // Klasse Student class Student{ string _name; string _first_name; public: Student(string, string); string get_name(); string get_first_name(); ~Student(); void print(); void print(bool); }; Student::Student(string name, string first_name){ _name = name; _first_name = first_name; cout << "Parametrisierter Konstruktor Student: "<< _first_name << " " << _name << endl; } string Student::get_name(){ return _name; } string Student::get_first_name(){ return _first_name; } Student::~Student(){ cout << "Destruktor Student: " << _first_name << " " << _name << endl; } void Student::print(){ cout << "print() ohne Parameter; Student: " << _first_name << " " << _name << endl; } void Student::print(bool zeilenumbruch){ if(zeilenumbruch == true){cout << "print() mit Parameter; Student: " << _first_name << " " << _name << endl;} if(zeilenumbruch == false){cout << "print() mit Parameter; Student: " << _first_name << " " << _name;} } // Klasse Employee class Employee{ string _name; string _first_name; public: Employee(string name, string first_name) :_name(name), _first_name(first_name) { cout << "Parametrisierter Konstruktor Employee: " << _first_name << " " << _name << endl; } Employee() : Employee("Mustermann", "Erika"){ cout << "Standardkonstruktor Employee: " << _first_name << " " << _name << endl; } Employee(Student _student) :_name(_student.get_name()), _first_name(_student.get_first_name()) { cout << "Konvertierungskonstruktor Employee: " << _first_name << " " << _name << endl; } ~Employee(){ cout << "Destruktor Employee: " << _first_name << " " << _name << endl; } void print(){ cout << "print() ohne Parameter; Mitarbeiter: " << _first_name << " " << _name << endl; } void print(bool zeilenumbruch){ if(zeilenumbruch == true){cout << "print() mit Parameter; Mitarbeiter: " << _first_name << " " << _name << endl;} if(zeilenumbruch == false){cout << "print() mit Parameter; Mitarbeiter: " << _first_name << " " << _name;} } }; int main(int argc, char *argv[]) { Student stud_mustermann = Student("Mustermann", "Max"); Employee empl_mustermann = Employee(stud_mustermann); Employee mit_default = Employee(); stud_mustermann.print(); stud_mustermann.print(true); empl_mustermann.print(); mit_default.print(); Student *p_stud_mustermann = nullptr; cout << "Block wird betreten" << endl; { p_stud_mustermann = new Student("Mustermann", "Markus"); p_stud_mustermann->print(true); } cout << "Block wurde verlassen" << endl; delete p_stud_mustermann; return 0; }
Vielen dank schon mal für`s Zeit nehmen und helfen.
-
https://en.cppreference.com/w/cpp/language/rule_of_three
Außerdem lass das mit dem new/delete einfach ganz sein.
-
Danke für die schnelle Antwort. Kann ich leider nicht, die main Funktion ist vorgeben und darf nicht modifiziert werden. Ich habe mir jetzt die Rule of three/five/zero durchgelesen, verstehe aber nicht so ganz wie mir das weiterhelfen kann.
-
Da werden Kopien von deinen Objekten erzeugt, aber du bekommst davon nix mit, weil du das Kopieren nicht loggst. Diese Kopien werden am Ende ihrer Lebenszeit ganz normal über deinen Destruktor aufgeräumt, was du wiederum loggst.. Da mehr Instanzen deiner Klassen existieren als du mitbekommst, bekommst du mehr Destruktoraufrufe als du erwartest.
Das ist erst einmal ganz normal und auch nicht schlimm, dass da an Stellen Kopien erzeugt werden (Es ist aber prinzipiell interessant unter welchen Umständen das warum passiert, aber gerade nicht das Thema). Da deine Klasse derzeit keine eigenen Ressourcen hält, geht da auch nix schief. Es ist nur eine Unzulänglichkeit in deinem Logging. Aber wenn deine Klasse jemals Ressourcen halten sollte (und wenn dein Lehrer ernsthaft solche new/delete Kombos zeigt, wird er sicher nicht die Rule of Zero kennen), dann wäre es falsch, aus den Gründen, die der Artikel erklärt.
-
Employee(Student _student) :_name(_student.get_name()), _first_name(_student.get_first_name()) { cout << "Konvertierungskonstruktor Employee: " << _first_name << " " << _name << endl; }
Schau hier in die erste Zeile deines Konvertierungskonstruktor. Der Parameter
_student
wird per KOPIE genommen. Das heißt, zum Aufrufen dieser Funktion wird der Student kopiert, auf der Kopie wirdget_name
undget_first_name
aufgerufen und dann wird die Kopie wieder gelöscht, wenn der Employee-Konstruktor verlassen wird.Nimm stattdessen eine konstante Referenz als Paramter, also:
Employee(const Student& student)
. (auch ohne_
, denn den scheinst du doch für Member-Variablen zu nutzen)Aber Achung: deinen Funktionen wie
get_name
fehlt dasconst
, um zu markieren, dass diese den Studenten nicht ändern. Stattclass Student{ string get_name();
musst du schreiben:
class Student{ string get_name() const;
if(zeilenumbruch == true)
Ein Vergleich einer bool-Variablen mit
true
ergibt wenig Sinn. Einfachif (zeilenumbruch) ...
und für denfalse
-Fallif (!zeilenumbruch) ...
(bzw. hier kannst du einfachelse
verwenden).
-
Super, danke euch beiden, ihr habt mir wirklich sehr geholfen.