Adressbuch: Vererbung Designfrage



  • Abend,
    Da ich gerade bei Vererbung und Laufzeitpolymorph angelangt bin wollte ich ein Adressbuch schreiben zur Übung. Hier Beispielcode mit Frage.

    class Person
    	{
    	public:
    		Person() : adress(""), first_name(""), last_name(""), age(-1), call_number(-1) {	}
    		~Person() { }
    		void set_adress(std::string name) { adress = name; }
    		void set_first_name(std::string name) { first_name = name; }
    		void set_last_name(std::string name) { last_name = name; }
    		void set_age(int age) { this->age = age; }
    		void set_call_number(int number) { call_number = number; }
    	protected:
    		std::string adress;
    		std::string first_name;
    		std::string last_name;
    		int age;
    		int call_number;
    	};
    
    	class Student : public Person
    	{
    	public:
    		Student() : grade(-1), school_name("") { }
    		~Student() { }
    		void set_grade(int grade) { this->grade = grade; }
    		void set_school_name(std::string school) { school_name = school; }
    	private:
    		int grade;
    		std::string school_name;
    	};
    	class Employee : public Person
    	{
    	public:
    		Employee() : company("") { }
    		~Employee() { }
    		void set_company(std::string name) { company = name; }
    	private:
    		std::string company;
    	};
    
    	class Adress_Book
    	{
    	public:
    		Adress_Book() { }
    		~Adress_Book() { }
    		void add_entry(Person new_entry) { this->Entry_Person.push_back(new_entry); }
    		//void add_entry(Student new_entry) {  }
    		//void add_entry(Employee new_entry) { }
    
    	private:
    		//std::vector<Student> Entry_Student;
    		//std::vector<Employee> Entry_Employee;
    		std::vector<Person> Entry_Person;
    	};
    

    Problem: Nehmen wir an ich erstelle ein Objekt der Klasse Student und möchte es an ein Objekt vom Typ Adress_Book übergeben mit "add_entry". Da Student eine Art von Person ist kann ich ein Objekt vom Typ Student einer Schnittstelle übergeben, auch wenn ein Typ Person erwartet wird. Anschließend landet der Eintrag in meinen Vector Entry_Person.

    Wenn ich jetzt aber auf den String school_name über den Vector_Person zugreifen möchte kann ich nicht drauf zugreifen. Wird der Typ Student auf Typ Person gequetscht? Wie kann ich dennoch auf die Member von Student zugreifen? Muss ich es so handhaben wie die Zeilen im Code die kommentiert sind? Oder gibt es einen besseren Weg es zu designen? Finde es nicht wirklich toll mit 3 Vectoren und wenn ich noch eine Art von Person hinzufügen möchte muss ich noch welche hinzufügen....



  • virtual user schrieb:

    Wird der Typ Student auf Typ Person gequetscht?

    Ja, das nennt man Slicing.

    virtual user schrieb:

    Wie kann ich dennoch auf die Member von Student zugreifen?

    Person nicht als Wert abspeichern, sondern als Zeiger (oder besser Smart-Pointer, dann musst du dich nicht um Speicherverwaltung kümmern). So hast du allerdings nur noch die Person -Schnittstelle zur Verfügung und kannst nicht mehr direkt auf Student -Eigenschaften zugreifen. Jedoch kann die Person -Klasse virtuelle Funktionen besitzen, die dann je nach abgeleiteter Klasse anders implementiert werden.



  • Danke für deine Antwort Nexus.
    Könntest du mir

    virtual user schrieb:

    Wie kann ich dennoch auf die Member von Student zugreifen?

    Person nicht als Wert abspeichern, sondern als Zeiger (oder besser Smart-Pointer, dann musst du dich nicht um Speicherverwaltung kümmern). So hast du allerdings nur noch die Person -Schnittstelle zur Verfügung und kannst nicht mehr direkt auf Student -Eigenschaften zugreifen. Jedoch kann die Person -Klasse virtuelle Funktionen besitzen, die dann je nach abgeleiteter Klasse anders implementiert werden.[/quote]

    das anhand einer Pseudoklasse illustrieren?



  • Man ruft auf dem Container Sachen auf wie "Druck Euch doch alle mal aus" oder so. Man ruft nur Sachen auf, die ALLE können.
    Allerdings wird der Student unter anderem seinen school_name ausdrucken. Weil er es kann. Ist ja seine Sache, wie er die virtuelle Methode genau macht. Dann ist alles gut. Es gibt überhaupt keinen Ärger damit.

    ~(Solange das Wurstbrot nicht von Supermarkt erbt. (Insiderwitz))~



  • #include <iostream>
    #include <iterator>
    #include <memory>
    #include <vector>
    
    struct A
    {
      virtual ~A() {} // virtual sorgt dafür, dass bei einem Aufruf die Funktion der Klasse aufgerufen wird, die sie zuletzt implementiert hat.
      virtual void foo() = 0; // Das "= 0" bedeutet "pure virtual", die Basisklasse bietet selbst also keine Implementierung.
    };
    
    struct B : public A
    {
      virtual ~B() { std::cout << "B Destruktor.\n"; }
      virtual void foo() { std::cout << "Hallo, B!\n"; }
    };
    
    struct C : public A
    {
      virtual ~C() { std::cout << "C Destruktor.\n"; }
      virtual void foo() { std::cout << "Hallo, C!\n"; }
    };
    
    int main()
    {
      std::vector<std::unique_ptr<A>> v;
      v.push_back(std::unique_ptr<B>(new B));
      v.push_back(std::unique_ptr<C>(new C));
      for (auto i = v.begin(); i != v.end(); ++i) // begin()/end() kann ideone.com nicht.
        (*i)->foo(); // * dereferenziert Iterator, -> unique_ptr.
    } // vector zerstört seine Member im Destruktor, der Destruktor von unique_ptr zerstört die Objekte.
    

    http://ideone.com/vAeQn


Anmelden zum Antworten