Vererbung und Konstruktor



  • Hi!

    Habe eine Anfänger-Verständnisfrage zu abgeleiteten Klassen bzw. dem zugehörigen Konstruktor.
    Aus einem Lehrbuch habe ich folgenden Header (Auszug) zur Basisklasse "GraphObj". (Der hier eingebundene header "Ort.h" sollte für das Verständnis nicht weiter wichtig bzw. selbsterklärend sein).

    #ifndef graphobj_h
    #define graphobj_h
    #include "ort.h"
    
    class GraphObj
    {
    public:
        GraphObj(const Ort &einOrt)
    		: Referenzkoordinaten(einOrt) {}
    
        // alten Bezugspunkt ermitteln und gleichzeitig neuen wählen
        Ort Bezugspunkt(const Ort &nO)
        {
            Ort temp = Referenzkoordinaten;
            Referenzkoordinaten = nO;
            return temp;
        }
    
    private:
        Ort Referenzkoordinaten;
    };
    #endif   // graphobj_h
    

    Der Header zur davon abgeleiteten Klasse (ebenfalls Auszug) sieht folgendermaßen aus (auch aus dem Lehrbuch):

    #ifndef strecke_h
    #define strecke_h strecke_h
    #include "graphobj.h"
    
    class Strecke : public GraphObj
    {
    public:
    	Strecke(const Ort &Ort1, const Ort &Ort2)
    	{
    		Bezugspunkt(Ort1);
    		Endpunkt = Ort2;
    	}
    	/*
    	Strecke(const Ort &Ort1, const Ort &Ort2)
    		: GraphObj(Ort1), Endpunkt(Ort2){}
    	*/
    
    private:
    	Ort Endpunkt;             
    };
    #endif // strecke_h
    

    Meine Frage bezieht sich nun auf den Konstruktor der abgeleiteten Klasse. Wenn ich es richtig verstanden habe, wird beim Aufruf des Konstruktors der abgeleiteten Klasse zunächst automatisch der Konstruktor der Basisklasse aufgerufen. Die in "Strecke.h" auskommentierte Konstruktorvariante mit Initialisierungsliste verstehe ich. Die Zeile

    Bezugspunkt(Ort1);
    

    in der tatsächlich implementierten Version verstehe ich allerdings nicht. Die Elementfunktion Bezugspukt gibt ein Objekt vom Typ Ort zurück. Muss denn dieses Objekt nicht noch irgendwie zugewiesen werden? Die abgeleitete Klasse hat zwar keinen Zugriff auf die privaten Daten der Basisklasse, aber woraus wird klar, dass die Rückgabe von "Bezugspunkt(Ort1);" den "Referenzkoordinaten" zugewiesen wird. Was wäre, wenn es mehrere private Attribute in der Basisklasse gäbe?

    Wäre nett, wenn mir das jemand erklären könnte.
    Danke schonmal vorab und sorry für den vielen Text.



  • Schau dir mal die Methode "GraphObj::Bezugspunkt()" an - die setzt die Referenzkoordinaten auf einen neuen Wert und liefert deren alten Wert zurück - sprich: Da ist die Zuweisung schon enthalten.

    btw glaube ich nicht, daß sich das Beispiel so compilieren lässt. GraphObj hat keinen Default-Konstruktor, also mußt du es aus der Initialisierungsliste heraus konstruieren.



  • Rückgabewerte von Methoden/Funktionen muss man nicht benutzen.
    Wenn ich mir das so anschau, dürfte das ganze hier nen Compilefehler geben, weil GraphObj keinen Standardkonstruktor hat, Strecke diesen aber benötigen würde bei der dort stehenden Klasse.

    edit: misst zu spät^^



  • Mit

    Bezugspunkt(Ort1);
    

    wird die Funktion 'Bezugspunkt' aus der Basisklasse aufgerufen. Der Rückgabewert der Funktion wird ignoriert (Das ist erlaubt.).
    Die Zuweisung des im Parameter übergebenen 'Ort1' an 'Referenzkoordinaten' erfolgt innerhalb der Funktion und hat nichts mit dem Rückgabewert zu tun.
    Dazu solltest Du Dir nochmal die Funktion 'Bezugspunkt' ansehen.

    DJohn



  • Danke für die Hinweise! Eingermaßen verstanden habe ich das jetzt, denke ich.

    Nachhaken möchte ich aber trotzdem noch einmal 😉 :

    Zunächst zur Ignorierung des Rückgabewerts der Funktion "Bezugspunkt". Normalerweise müsste diese Methode doch für ein Objekt aufgerufen werden, z.B.:

    x.Bezugspunkt(Ort1); // x sei vom Typ GraphObj
    

    Dass ich den Rückgabewert ignoriere äußert sich also schon darin, dass hier die Methode NICHT für ein bestimmtes Objekt aufgerufen wird, richtig??

    Dann zu eurer Anmerkung bezüglich des fehlenden Standarkonstruktors (Beispiel ist tatsächlich aus diesem Grund nicht compilierbar):
    ich denke das ist genau das, was mich irritiert hat. Die Methode "Bezugspunkt" führt nur die Zuweisung aus, allerdings ist zu diesem Zeitpunkt noch gar kein "GraphObj" mit seinem Attribut "Referenzkoordinaten" erzeugt worden. Wäre also ein Standardkonstruktor für "GraphObj" vorhanden, würde beim Aufruf des Konstruktors von "Strecke" der "Anfangspunkt" erzeugt und mit (beliebigen) Werten initialisiert. Anschließend erfogte die Zuweisung neuer Werte über die Anweisung

    Bezugspunkt(Ort1);
    

    Ist das korrekt?



  • Nanuq schrieb:

    Dass ich den Rückgabewert ignoriere äußert sich also schon darin, dass hier die Methode NICHT für ein bestimmtes Objekt aufgerufen wird, richtig??

    die funktion wird für ein bestimmtes objekt aufgerufen, nämlich für *this.

    Bezugspunkt(Ort1);
    //ist äquivalent zu
    this->Bezugspunkt(Ort1);
    

    und dass das funktioniert liegt daran, dass Strecke von GraphObj abgeleitet ist.

    zum rückgabewert: der kann einfach ignoriert werden (also nicht weiterverarbeitet)
    beispiel

    int foo ()
    {
     return 42;
    }
    
    int main ()
    {
       foo(); //ich interessiere mich einfach nicht für den rückgabewert, also wozu sollte ich den in einer variable speichern?
    }
    

    ...
    Ist das korrekt?

    ja.



  • davie schrieb:

    ...
    Ist das korrekt?

    ja.

    nicht ganz, denn zu dem zeitpunkt, wo Bezugspunkt aufgerufen wird, gäbe es schon ein GraphObj. aber da sich die frage nicht stellt, weil der code ohne standardkonstruktor nicht kompiliert bleibe ich bei ja.



  • Hervorragend, dann habe ich es jetzt engültig begriffen.

    Herzlichen Dank!


Anmelden zum Antworten