[erklärung] Klassen - Vererbung



  • Hallo Gemeinde,

    ich dachte eigentlich das ich das Thema verstanden habe, da ich das ja auch aktiv nutze, jedoch treten jetzt verhäuft Zweifel und Fragen auf.

    Ich habe hier ein kleines Beispiel-Modul:

    class.h

    #ifndef CLASS_H_
    #define CLASS_H_
    
    class A
    {
    public:
    	A() {};
    	~A() {};
    	void setNumberOne( int one );
    	void setNumberTwo( int two );
    	int getResult();
    protected:
    	int numberOne;
    	int numberTwo;
    	int numberResult;
    	void calculate();
    };
    
    class B : public A
    {
    public:
    	B( A instance );
    	~B() {};
    	void setNumberThree( int three );
    private:
    	int numberThree;
    	A object;
    protected:
    	void calculate();
    };
    
    #endif /*CLASS_H_*/
    

    class.cpp

    #include "class.h"
    
    void A::setNumberOne( int one )
    {
    	numberOne = one;
    }
    
    void A::setNumberTwo( int two )
    {
    	numberTwo = two;
    
    	calculate();
    }
    
    void A::calculate()
    {
    	numberResult = numberOne + numberTwo;
    }
    
    int A::getResult()
    {
    	return numberResult;
    }
    
    B::B( A instance )
    {
    	object = instance;
    }
    
    void B::setNumberThree( int three )
    {
    	numberThree = three;
    
    	calculate();
    }
    
    void B::calculate()
    {
    	numberResult = object.getResult() + numberThree;
    }
    

    main.cpp

    #include <iostream>
    #include "class/class.h"
    
    using namespace std;
    
    int main()
    {
    	A a;
    
    	a.setNumberOne(2);
    	a.setNumberTwo(3);
    
    	cout << "Result: " << a.getResult() << "\n" << endl;
    
    	B b( a );
    	b.setNumberThree(5);
    	cout << "Result: " << b.getResult() << "\n" << endl;
    
    	return 0;
    }
    

    Das Beispiel funktioniert und ist denke ich auch verständlich, so das ich da nicht näher darauf eingehen muss.

    Farage1:
    Wie man sehen kann, gibt es

    void A::calculate();
    

    und

    void B::calculate();
    

    Die Funktion aus der Klasse B ist nur leicht verändert. Es ist ja so, das wenn man Funktionen bei der Vererbung überschreiben will, das diese mit

    virtual
    

    gekennzeichnet werden müssen. Warum funktioniert das bei mir ohne diese Kennzeichnung? Wozu sollte ich

    virtual
    

    nutzen?

    Frage2:
    Ich habe es noch nie gebraucht oder besser gesagt noch nie benutzt. Die Klasse B leitet von A ab (public). Ich kann ja B auch von A als private ableiten, nur was bringt mir das? Ich habe festgestellt, das ich dann nicht mehr (von B aus) auf die Memberfunktion

    int A::getResult();
    

    zugreifen kann.

    Bucherklärung zu Frage2:

    Ist die Sichtbarkeit der Vererbung privat, so erbt die Klasse B zwar die Funktionalität der Klasse A, sie erbt jedoch nach außen keine Verpflichtungen der Klasse A

    Damit ist bestimmt alles gesagt, jedoch begreife ich das nicht. Könnte mich da jemand erhellen?

    Vielen Dank für die Hilfe

    so long
    jd



  • Hi,

    auch ohne ein derart "geschwätziges" Beispiel 😉 kann man sagen: ohne "virtual" ist so ein Konstrukt selten das, was man wirklich will. Außerdem hast Du noch weitere Absonderlichkeiten da drin:
    1.) Ein Member vom Typ der Basisklasse ... warum eigentlich, wo doch ein B automatisch schon ein A-Subobjekt "im Bauch" hat ?
    2.) Ist Dir bewusst, dass im B-Ctor nur ein Kopie des übergebenen a-Objekts "gezogen" wird ?

    Gruß,

    Simon2.



  • Ja, das ist mir beides klar... mir geht es aber nicht darum wie zweckdienlich das ist, oder ob was kopiert wird oder nicht. Mir geht es um die Problematik mit virtual. Wie ich in meinem ersten Beitrag oben schon geschrieben habe und um die private Vererbung.



  • jd schrieb:

    Wozu sollte ich

    virtual
    

    nutzen?

    class A
    {
    	public:
    		virtual void a( ) { std::cout << "Klasse A" << std::endl; }
    };
    
    class B : public A
    {
    	public:
    		virtual void a( ) { std::cout << "Klasse B" << std::endl; }
    };
    
    class C : public A
    {
    	public:
    		virtual void a( ) { std::cout << "Klasse C" << std::endl; }
    };
    
    int main()
    {
    	A* pobj;		// Zeiger vom Typ A erstellen
    	pobj = new B;
    	pobj->a( );		// Ausgabe: "Klasse B"( ohne das Schlüsselwort virtual, würde hier "Klasse A" aufgerufen )
    	delete pobj;
    
    	pobj = new C;
    	pobj->a( );             // Ausgabe "Klasse C"
    
    	delete pobj;
    
    }
    

    -> kurzum: virtuelle Funktionen definieren Schnittstellen für
    alle abgeleiteten Klassen ihres Typs( auch wenn diese bei der Festlegung der Basisklasse
    noch unbekannt sind )

    jd schrieb:

    ~A() {};

    Ausserdem sollte bei Abstrakten Klassen der Destruktor immer virtuell sein.

    jd schrieb:

    Ich kann ja B auch von A als private ableiten, nur was bringt mir das?

    meinst du damit eine Implementationsvererbung?
    Dies würde dann so aussehen:

    class A
    {
    	public:
    		void c( ) { std::cout << "funktion c" << std::endl; }
    		void d( ) { std::cout << "funktion d" << std::endl; }
    };
    class B : private A
    {
    	public:
    		using A::c; // diesmal wird nicht die Schnittstelle, sondern die Implementierung geerbt( nur die Funktion c )
    };
    /*class C : public B // dieses Objekt würde die funktion c nicht beinhalten
    {
    };*/
    int main()
    {	
    	B b;
    	b.c( );	// b.d( ) ist nicht möglich, da nur die funktion c vererbt wurde
    
    }
    

    -> Bei Privater Vererbung darf die Unterklasse die Funktion benutzen, die Objekte dieser aber nicht.



  • Danke für die Erklärung jetzt wird mir einiges klarer.


Anmelden zum Antworten