Warum immer BasePtr/-referenz bei Plolymorphie?



  • Beispiel:

    Base* basePtr;
    Derived1 eckig;
    Derived2 rund;
    
    basePtr=&eckig;
    basePtr=&rund
    

    Warum wird bei Polymorphie immer ein Zeiger, oder eine Referenz auf die Basisklasse verwandt?
    Warum nicht eine "einfache" Variable (Base base;)



  • Beginner schrieb:

    Beispiel:

    Base* basePtr;
    Derived1 eckig;
    Derived2 rund;
    
    basePtr=&eckig;
    basePtr=&rund
    

    Warum wird bei Polymorphie immer ein Zeiger, oder eine Referenz auf die Basisklasse verwandt?
    Warum nicht eine "einfache" Variable (Base base;)

    kannst natürlich auch die Base nehmen. kein problem. bis auf's slicing.

    class Vogel{
       double masse;
    public:
       virtual void printAt(ostream& cout){
          cout<<"Vogel mit Masse "<<masse<<"kg";
       }
       ...
    };
    class Singvogel:public Vogel{
       string melodei;
    public:
       virtual void printAt(ostream& cout){
          cout<<"Singvogel mit Masse "<<masse<<"kg und der Melodei "<<string;
       }
    };
    

    und nu

    Singvogel s(0.1,"trärällälä.wav");
    

    jetzt kann ich gut machen:

    Vogel* v=&s;//nur 4 byte, der echte inhalt steht in s und ich zeige auf ihn
    s->printAt(cout);
    

    aber versuche ich mal

    Vogel v=s;//echt 8 byte (double)
    s.printAt(cout);
    

    was ist im objekt v los? es hat nur einen double drin. denn seizeof(Vogel)==sizeof(double)+sizeof(versteckter vptr). da ist nicht mehr. die melodei passt einfach nicht rein. der vogel kann einfach die meolei nicht anzeigen, weil kein speicherplatuz dafür reserviert wurde. es ist ein *Vogel* und kein *Singvogel*. bei dieser zuweisung ist das slicing passier. alle vogel-eigenschaften des singvogels s wurden genommen und in den vogel v kopiert. aber für die zusätzlichen singvogel-eigenschaften war kein platz mehr. die wurden einfach weggelassen. und damit es keinen abkacker gibt bei printAt, wurde auch noch dafür gesorgt, daß Vogel::printAt aufgerufen wird. es ist einfach ein *Vogel* und kein singvogel mehr.



  • Eine weitere Sache ist, dass Basisklassen durchaus abstrakt sein können (Stichwort ➡ rein virtuelle Funktionen). Und diese kann man nunmal nicht instanzieren.



  • @volkard:

    jetzt kann ich gut machen:
    C/C++ Code:
    Vogel* v=&s;//nur 4 byte, der echte inhalt steht in s und ich zeige auf ihn
    s->printAt(cout);
    C/C++ Code:
    Vogel* v=&s;//nur 4 byte, der echte inhalt steht in s und ich zeige auf ihn
    s->printAt(cout);
    C/C++ Code:
    Vogel* v=&s;//nur 4 byte, der echte inhalt steht in s und ich zeige auf ihn
    s->printAt(cout);

    aber versuche ich mal
    C/C++ Code:
    Vogel v=s;//echt 8 byte (double)
    s.printAt(cout);
    C/C++ Code:
    Vogel v=s;//echt 8 byte (double)
    s.printAt(cout);
    C/C++ Code:
    Vogel v=s;//echt 8 byte (double)
    s.printAt(cout);

    was ist im objekt v los? es hat nur einen double drin. denn seizeof(Vogel)==sizeof(double)+sizeof(versteckter vptr)..

    Das verstehe ich nicht so ganz 😞 . Koenntest du das evtl, noch mal erklaeren?

    die melodei passt einfach nicht rein. der vogel kann einfach die meolei nicht anzeigen, weil kein speicherplatuz dafür reserviert wurde. es ist ein *Vogel* und kein *Singvogel*. bei dieser zuweisung ist das slicing passier. alle vogel-eigenschaften des singvogels s wurden genommen und in den vogel v kopiert. aber für die zusätzlichen singvogel-eigenschaften war kein platz mehr. die wurden einfach weggelassen. und damit es keinen abkacker gibt bei printAt, wurde auch noch dafür gesorgt, daß Vogel::printAt aufgerufen wird. es ist einfach ein *Vogel* und kein singvogel mehr.

    Aber das alles ist bei der Pointerversion doch nicht anders.... Oder doch?



  • Zitat:
    die melodei passt einfach nicht rein. der vogel kann einfach die meolei nicht anzeigen, weil kein speicherplatuz dafür reserviert wurde. es ist ein *Vogel* und kein *Singvogel*. bei dieser zuweisung ist das slicing passier. alle vogel-eigenschaften des singvogels s wurden genommen und in den vogel v kopiert. aber für die zusätzlichen singvogel-eigenschaften war kein platz mehr. die wurden einfach weggelassen. und damit es keinen abkacker gibt bei printAt, wurde auch noch dafür gesorgt, daß Vogel::printAt aufgerufen wird. es ist einfach ein *Vogel* und kein singvogel mehr.

    Aber das alles ist bei der Pointerversion doch nicht anders.... Oder doch?

    Genau das, es wird ja keine neue Variable angelegt sondern lediglich ein
    zusätzlicher Verweis vom Typ Vogel auf den bestehenden Singvogel geliefert.
    Es geht also nichts verloren. 🙂

    Ein cast auf den Singvogel und alles wieder da. 😉


Anmelden zum Antworten