Programmablauf C++



  • Hi,
    ich sitz nun schon ne weile vor nem programm und versteh den ablauf nicht. vielleicht kann mir hier jemand helfen ein paar bemerkungen in den quellcode schreiben wo was, wie und warum übergeben,vererbt etc. wird. ich hab leider nur ein wenig ahnung in C aber da gabs das mit den klassen nicht zumindest nicht in dem umfang.
    Ich nehm vorweg das es sich um ein lehrbeispiel handelt also das programme selber hat keinen großen nutzen.

    also hier nun der quellcode:

    #include <iostream.h>
    class A
    { public: void druck(){cout<<"\niA="<<i;};
    int get(){return i;}
    A(int k=0){i=k;}
    protected: int i;
    };
    class B : public A
    { private: A a; int i;
    public: void druck(){cout<<"\niB="<<i; a.druck();A::druck();};
    A get(){return a;}
    B(A elem,int ka,int k):a(elem.get()),A(ka){i=k;}
    B(){}
    };
    class C : public B
    { public: void druck(){cout<<"\nC: ";B::druck();};
    C(B erb1,A x,int erb2):B(erb1.get(),x.get(),erb2){}
    C(){}
    };
    void main()
    { A a1,a2(4); B b(a2,2,3); a1.druck(); a1=b.get();
    C c1,c2(b,a1,7); b.druck(); c2.druck();
    }

    ich würd mich freuen wenn jemand mir helfen kann.



  • ich würde vorschlagen du strukturierst das programm erstmal

    #include <iostream>
    using namespace std;
    
    class A
    {
        public:
            void druck()
            {
                cout<<"\niA="<<i;
            }
    
            int get()
            {
                return i;
            }
    
            A(int k=0){i=k;}
    
        protected: 
            int i;
    }
    
    class B : public A
    { 
        private: 
            A a; 
            int i;
    
        public: 
            void druck()
            {
                cout<<"\niB="<<i;
                a.druck();
                A::druck();
            }
    
            A get()
            {
                return a;
            }
    
            B(A elem,int ka,int k) : a(elem.get()), A(ka)
            {
                i=k;
            }
            B(){ }
    }
    
    class C : public B
    { 
        public: 
            void druck()
            {
                cout<<"\nC: ";
                B::druck();
            }
    
            C(B erb1,A x,int erb2):B(erb1.get(),x.get(),erb2)
            {
            }
            C(){}
    }
    
    int main()
    { 
        A a1,a2(4); 
        B b(a2,2,3); 
        a1.druck(); 
        a1=b.get();
        C c1,c2(b,a1,7);
        b.druck();
        c2.druck();
    }
    

    dann kompilierst du und guckst dir die ausgabe an

    ausgabe schrieb:

    iA=0
    iB=3
    iA=4
    iA=2
    C:
    iB=7
    iA=4
    iA=4

    und dann überlegst du dir wie das denn wohl zustande kommen könnte, wenn du konkret etwas davon nicht verstehst frag nochmal 👍



  • Danke erstmal für die schnelle reaktion.

    So hab nun wieder ne weile drauf geschaut und auch ein weiteres mal kompiliert aber ich raffs ni...
    kannst mir vielleicht ein paar tips geben wie man da ran gehen könnte.

    danke



  • Die Vererbung lässt sich am besten anhand der realen Welt beschreiben. Du siehst einen Dackel. Wenn du ein Wenig weiter blickst, bemerkst du, dass der Dackel eine Art von Hund ist, d.h. er besitzt auch Eigenschaften und Methoden des Hundes. Der Hund wiederrum gehört zur Familie der Säugetiere. Der Hund besitzt somit auch ein paar Eigenschaften und Methoden der Säugetiere.
    Genau so ist es in der OOP.

    Du hast eine Klasse Hund, diese hat ein paar Eigenschaften und Methoden, die eine Klasse Dackel ebenfalls braucht, denn ein Dackel ist ja ein Hund. Um den Code nicht zweimal zu schreiben, vererbst du einfach die Datenelemente des Hundes auf den Dackel. Dies geht so:

    Du hast eine Klasse Hund, die so aussieht:

    class Hund
    {
            private:
                    std::string name;
                    unsigned int alter;
                    unsigned int anzahlBeine;
            public:
                    Hund(const std::string& n, const unsigned int a, const unsigned int aB) : name(n), alter(a), anzahlBeine(aB) { }
                    void setName(const std::string& n) { name = n; }
                    std::string getName() const { return name; }
                    void setAlter(const unsigned int a) { alter = a; }
                    unsigned int getAlter() const { return alter; }
                    void setAnzahlBeine(const unsigned int aB) { anzahlBeine = aB; }
                    unsigned int getAnzahlBeine() const { return anzahlBeine; }
    };
    

    Nun hast du noch eine Klasse Dackel. Alle Datenelemente der Klasse Hund sollen auf die Klasse Dackel vererbt werden. Zusätzlich soll der Klasse Dackel noch eine Methode Kläffen hinzugefügt werden.

    class Dackel : public Hund
    {
            public:
                   // Methoden von Hund sind schon enthalten.
                   Dackel(const std::string& n, const unsigned int a, const unsigned int aB) : Hund(n, a, aB) { }
                   void klaeffen() const { std::cout << "Klaeff-Klaeff-Klaeff\n"; }
    };
    

    Nun können wir ein Objekt der Klasse Hund definieren. Dieses besitzt dann alle Eigenschaften und Methoden der Klasse Hund. Wir können aber auch ein Objekt der Klasse Dackel definieren. Dieses besitzt dann alle Methoden und Eigenschaften des Hundes plus die zusätzlichen Eigenschaften und Methoden aus der Klasse Dackel.

    Beispiel:

    int main()
    {
            Dackel dackel1("frodo", 12, 4);
            std::cout << "Frodo ist " << dackel1.getAlter() << " Jahre alt\n";
            dackel1.setAlter(13);
            std::cout << "Frodo ist jetzt " << dackel1.getAlter() << " Jahre alt\n";
            dackel1.klaeffen();
    
            return 0;
    }
    

    //Edit: Die sogenannte public-Vererbung besagt, dass alle public-Elemente der Klasse Hund auch in der Klasse Dackel öffentlich gemacht werden. Die privaten Daten-Elemente der Basisklasse (Klasse Hund) bleiben aber weiterhin durch die Zugriffe von außen geschützt. Du kannst also nicht aus der Klasse Dackel heraus auf die privaten Datenelemente der Klasse Hund zugreifen. Um das zu tun, musst du Zugriffsmethoden implementieren. (Wie im Beispiel)

    (Bei der Vererbung gibt es noch viel mehr, wie z.B. Redefinition von Methoden etc... Dazu schau am besten in ein gutes C++-Buch und/ oder hier und hier)

    Caipi



  • ich dank dir erstmal Caipi hab die grundzüge nun endgültig verstanden nur ich komm ni drauf was die übergabevariablen in "int main()" machen oder wo sie hingehen (bei meinem lehrbsp.)

    int main()
    {
    A a1,a2(4); <-- wo kommt a1 her und wo gehts hin das gl. mit a2 usw.
    a1.druck(); müsst ich dies nicht deklarieren oder mach ich das hiermit
    a1=b.get(); Was macht eigentlich "a1.druck()" is das auch ein aufruf ??
    C c1,c2(b,a1,7);
    b.druck();
    c2.druck();
    }

    vielleicht kannst mir das ja noch erklären dann platzt vielleicht der knoten 🤡

    danke...



  • erstmal vorweg: achte auf deine formatierungen des textes es ließt sich grauenvoll. nun zu deinem problem:

    dropse schrieb:

    ...
    A a1,a2(4); //'a1' und 'a2' sind objekte von 'A'
    a1.druck(); //aufruf der methode 'druck' des objektes 'a1'
    a1=b.get(); //was 'a1.druck()' mach steht in der klasse 'A'
    ...



  • Caipi schrieb:

    Die Vererbung lässt sich am besten anhand der realen Welt beschreiben. Du siehst einen Dackel. Wenn du ein Wenig weiter blickst, bemerkst du, dass der Dackel eine Art von Hund ist, d.h. er besitzt auch Eigenschaften und Methoden des Hundes. Der Hund wiederrum gehört zur Familie der Säugetiere. Der Hund besitzt somit auch ein paar Eigenschaften und Methoden der Säugetiere.
    Genau so ist es in der OOP.

    Das Beispiel ist aber ein wenig unglücklich, oder? Ich meine inwiefern unterscheidet sich ein Dackel von einem Hund, so dass man von ihm erben müsste? Ein Dackel ist ein Hund und somit eine Instanz davon.



  • 🙂 schrieb:

    Caipi schrieb:

    Die Vererbung lässt sich am besten anhand der realen Welt beschreiben. Du siehst einen Dackel. Wenn du ein Wenig weiter blickst, bemerkst du, dass der Dackel eine Art von Hund ist, d.h. er besitzt auch Eigenschaften und Methoden des Hundes. Der Hund wiederrum gehört zur Familie der Säugetiere. Der Hund besitzt somit auch ein paar Eigenschaften und Methoden der Säugetiere.
    Genau so ist es in der OOP.

    Das Beispiel ist aber ein wenig unglücklich, oder? Ich meine inwiefern unterscheidet sich ein Dackel von einem Hund, so dass man von ihm erben müsste? Ein Dackel ist ein Hund und somit eine Instanz davon.

    jo..
    nur dass in vielen büchern der hund eine basisklasse, und die kindhunde unterklassen sind *g*

    alle hunde können wedeln, essen, laute von sich geben und haben beine, nur der dackel spezialisiert sich durchs kläffen, der boxer durchs süffen beim essen, und der schäferhund bellt tief und hallend... ladida

    ist immer schwer, was geeignetes zu finden für ableitung, ich mag die symbole als basisklasse, aber auch das ist disktutierbar.



  • 🙂 schrieb:

    Caipi schrieb:

    Die Vererbung lässt sich am besten anhand der realen Welt beschreiben. Du siehst einen Dackel. Wenn du ein Wenig weiter blickst, bemerkst du, dass der Dackel eine Art von Hund ist, d.h. er besitzt auch Eigenschaften und Methoden des Hundes. Der Hund wiederrum gehört zur Familie der Säugetiere. Der Hund besitzt somit auch ein paar Eigenschaften und Methoden der Säugetiere.
    Genau so ist es in der OOP.

    Das Beispiel ist aber ein wenig unglücklich, oder? Ich meine inwiefern unterscheidet sich ein Dackel von einem Hund, so dass man von ihm erben müsste? Ein Dackel ist ein Hund und somit eine Instanz davon.

    Ok, wahrscheinlich hast du recht. Was hätte ich den deiner Meinung nach für Beispiele nehmen sollen? A und B?
    Und doch, der Dackel spezifiziert sich vom Hund (zumindest ein wenig) z.B. durch kurze Beine :p. Aber mir hat eine Methode Kläffen gereicht 🙂 (Faulheit)

    Caipi



  • 🙂 schrieb:

    Caipi schrieb:

    Die Vererbung lässt sich am besten anhand der realen Welt beschreiben. Du siehst einen Dackel. Wenn du ein Wenig weiter blickst, bemerkst du, dass der Dackel eine Art von Hund ist, d.h. er besitzt auch Eigenschaften und Methoden des Hundes. Der Hund wiederrum gehört zur Familie der Säugetiere. Der Hund besitzt somit auch ein paar Eigenschaften und Methoden der Säugetiere.
    Genau so ist es in der OOP.

    Das Beispiel ist aber ein wenig unglücklich, oder? Ich meine inwiefern unterscheidet sich ein Dackel von einem Hund, so dass man von ihm erben müsste? Ein Dackel ist ein Hund und somit eine Instanz davon.

    Das sagt ja auch schon die Definition der öffentlichen Vererbung, denn öffentliche Vererbung steht für "ist ein" (vgl. Effectiv C++). Und wie schon gesagt verhalten sich alle Hunderrassen etwas anders und sehen vor allem auch anders aus.



  • Caipi schrieb:

    Du hast eine Klasse Hund, diese hat ein paar Eigenschaften und Methoden, die eine Klasse Dackel ebenfalls braucht, denn ein Dackel ist ja ein Hund. Um den Code nicht zweimal zu schreiben, vererbst du einfach die Datenelemente des Hundes auf den Dackel.

    Das ist in der Regel keine gute Motivation für Vererbung. Öffentliche Vererbung ist nicht als low-level-Code-Wieverwendungsmechanismus gedacht. Dafür ist Komposition besser geeignet. Der große Bonus der Vererbung ist nicht, dass du in abgeleiteten Klassen weniger schreiben musst sondern, dass vorhandener Code ohne es zu wissen neuen Code verwenden kann.

    Sprich: du hast ein Framework (oder Teilsystem oder oder) das mit Hunden arbeiten kann. Irgendwann in der Zukunft baust du dir einen Dackel. Der Bonus: da ein Dackel ein Hund ist, kann der Framework-Code auch mit deinem Dackel umgehen (obwohl das Framework nix von Dackeln weiß). Der entscheidene Punkt ist also die Wiederverwendung des Framework-Codes nicht die des Basisklassencodes in der abgeleiteten Klasse.
    Oder anders: in der öffentliche Vererbung sollte es also in der Regel um Wiederverwendung von Verhalten gehen. Nicht um Wiederverwendung von Daten.

    Oder noch anders:

    Don't inherit publicly to reuse code (that exists in the base class); inherit publicly in to to be reused (by existing code that already uses base objects polymorphically).

    (H. Sutter, A. Alexandrescu "C++ Coding Standards).



  • ich versteh die Objekterzeugung in main nicht so ganz. Brauche ich für die Klasse A wirklich kein Konstruktor schreiben und ab wann kann ich mich nicht mehr auf den automatischen Konstruktor verlassen?



  • hm da ich gerade auch bei vererbung bin wollte ich fragen ob ich,
    aufgrund der kommentare, den vererbungmechanismus richtig verstanden habe

    hier der code:

    #include <iostream.h>
    
    class kfz
    {
    	private:
    		int tuev;				//monate bis tüv abgelaufen
    		int asu;				//monate bis asu abgelaufen
    	public:
    		void kfz::eingabe();
    		void kfz::ausgabe();
    		kfz();
    		~kfz();
    };
    
    class pkw:private kfz			//nur private werte von kfz übernehmende klasse pkw
    {
    	private:
    		int personen;
    		int tueren;
    };
    
    class lkw:private kfz			//nur private werte von kfz übernehmende klasse lkw
    {
    	private:
    		int achsen;
    		int traglast;
    };
    
    class krad:public kfz			//nur public werte von kfz übernehmende klasse krad
    {
    	private:
    		int zylinder;
    		int gaenge;
    };
    
    kfz::kfz()						//standartkonstruktor
    {
    };
    
    kfz::~kfz()						//standartdestruktor
    {
    };
    
    void kfz::eingabe()				//funktion eingabe
    {
    }
    
    void kfz::ausgabe()				//funktion ausgabe
    {
    }
    
    void main()						//main
    {
    }
    

    mfg rum



  • Hallo

    ich würde die Eigenschaften

    int personen;
    int tueren;
    int achsen;
    int traglast;
    int zylinder;
    int gaenge;
    

    direkt der Basisklasse kfz zuordnen, denn sowas hat ja jedes Kfz. Und wenn nicht, dann eben 0 (Beispiel : Krad : Türen = 0).

    bis bald
    akari



  • ahh

    ja das ist'n guter ansatz, dann bräuchte ja theoretisch nur noch
    private vererbung einzusetzen und könnte mir dann aussuchen welche werte
    davon ich für die vererbten klassen nutzen möchte

    sehr schön; danke 😉



  • Leider hast du das nciht ganz richtig verstanden. Denn wenn ich deinen KJommentar im Code richtig verstanden habe, dann bist du der Meinung, dass bei privater Vererbung nur die provaten Elemente übernommen werden. Dem ist aber nicht so, denn es werde alle Elemente übernommen, diese aber zu privaten Elementen konvertiert.

    Aber du solltest jetz auch nicht bloß noch private Vererbung benutzem. denn dies kann ein großer Fehler sein und zu Problemen führen. Stattdessen sollte man, wenn man eine Klasse benutzen will, aber nicht mit öffentlicher Vererbung arbeiten kann, eine Instanz dieser Klasse in der Klasse erzeugen, in der man sie verwenden will und dann dieses Objekt verwenden.

    Bei KFZ würde ich wohl eher zu öffentlicher Vererbung denken, da ja ein Auto ein KFZ ist und nicht durch eines implementiert wird.



  • ok

    das wirft ein anderes licht auf das ganze
    also ich kann ruhig öffentlich vererben, hab den code nur geschrieben
    um eine basis zu haben zum üben und wenn alles vererbt und dann nur
    in den entsprechenden vererbungstyp konvertiert wird, liegt wieder eine
    andere situation vor als ich dachte

    ich werd den kompletten code neu schreiben
    da jetz andere rahmenbedingungen herrschen als ich dachte

    danke für den hinweis 😉
    mfg rum



  • also ich hab den code mal umgeschrieben, und hab festgestellt das es genauso ist wie du gesagt hast

    #include <iostream.h>
    
    class kfz
    {
    	private:
    		int typ;
    		int tuev;						//alle - monate bis tüv abgelaufen
    		int asu;						//alle - monate bis asu abgelaufen
    		int personen;					//pkw only
    		int tueren;						//pkw only
    		int achsen;						//lkw only
    		int traglast;					//lkw only
    		int hubraum;					//krad only
    		int gaenge;						//krad only
    	public:
    		void kfz::eingabe();
    		void kfz::ausgabe();
    		kfz();
    		~kfz();
    };
    
    class pkw:public kfz					//alle werte von kfz übernommen und in public umgewandelt
    {
    };
    
    class lkw:public kfz					//alle werte von kfz übernommen und in public umgewandelt
    {
    };
    
    class krad:private kfz					//alle werte von kfz übernommen und in private konvertiert
    {
    };
    
    kfz::kfz()								//standartkonstruktor
    {
    };
    
    kfz::~kfz()								//standartdestruktor
    {
    };
    
    void kfz::eingabe()						//funktion eingabe
    {
    	cout<<"Bitte geben Sie den Typ des Fahrzeugs ein(PKW=1,LKW=2,KRAD=3): "<<endl;
    	cin>>typ;	
    	if (typ==1)							//eingabemaske für PKW
    		{
    			cout<<"Fahrzeug ist ein PKW"<<endl;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des TUEV ein: "<<endl;
    			cin>>tuev;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des ASU ein: "<<endl;
    			cin>>asu;
    			cout<<"Bitte geben Sie die maximale Anzahl der befoerderbaren Personen ein: "<<endl;
    			cin>>personen;
    			cout<<"Bitte geben Sie die Anzahl der Tueren ein: "<<endl;
    			cin>>tueren;
    		}
    	else if (typ==2)					//eingabemaske für LKW
    		{
    			cout<<"Fahrzeug ist ein LKW"<<endl;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des TUEV ein: "<<endl;
    			cin>>tuev;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des ASU ein: "<<endl;
    			cin>>asu;
    			cout<<"Bitte geben Sie die maximale Traglast(Tonnen) ein: "<<endl;
    			cin>>traglast;
    			cout<<"Bitte geben Sie die Anzahl der Achsen ein: "<<endl;
    			cin>>achsen;
    		}
    	else if (typ!=1 && typ!=2 && typ!=3)//wenn fallsch gewählt = ausgabe error
    		{
    			cout<<"ERROR ERROR ERROR"<<endl;
    		}
    	else								//eingabemaske für KRAD
    		{
    			cout<<"Fahrzeug ist ein KRAD"<<endl;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des TUEV ein: "<<endl;
    			cin>>tuev;
    			cout<<"Bitte geben Sie die Monate bis zum Ablaufen des ASU ein: "<<endl;
    			cin>>asu;
    			cout<<"Bitte geben Sie den Hubraum ein: "<<endl;
    			cin>>hubraum;
    			cout<<"Bitte geben Sie die Anzahl der Gaenge ein: "<<endl;
    			cin>>gaenge;
    		}
    }
    
    void kfz::ausgabe()						//funktion ausgabe
    {
    	if (typ==1)
    		{
    			cout<<"..PKW.."<<endl;
    		}
    	else if (typ==2)
    		{
    			cout<<"..LKW.."<<endl;
    		}
    	else
    		{
    			cout<<"..KRAD.."<<endl;
    		}
    }
    
    void main()								//main
    {
    	pkw fahrzeug1;
    	fahrzeug1.eingabe();
    	fahrzeug1.ausgabe();
    
    	krad fahrzeug2;
    	fahrzeug2.eingabe();
    	fahrzeug2.ausgabe();
    }
    

    bei der instanz fahrzeug2 meckert er nämlich wie erwartet:
    error C2248: "eingabe" : Kein Zugriff auf public Element, dessen Deklaration in der Klasse "kfz" erfolgte
    Siehe Deklaration von 'eingabe'

    demnach ist die in kfz als public funktion deklarierte funktion eingabe in
    private konvertiert wurden, wie es in der vererbung von krad auch steht

    oder hab ich irgendwo nochn denkfehler?

    ein digges danke an viande
    mfg rum



  • Dystopic schrieb:

    ich versteh die Objekterzeugung in main nicht so ganz. Brauche ich für die Klasse A wirklich kein Konstruktor schreiben und ab wann kann ich mich nicht mehr auf den automatischen Konstruktor verlassen?

    Du kannst, musst aber nicht, denn der Konstruktor in A impliziert durch das Default-Argument einen Default-Konstruktor. Du kannst also A obj oder A obj(4) schreiben. Im ersten Fall wird der gleiche Ctor aufgerufen wie im zweiten mit dem Unterschied, dass du im ersten Fall der Variablen i das Default-Argument zugewiesen wird und im zweiten Fall das übergebene Argument.

    //Edit: Seh grad, dein Post ist schon älter. Aber vielleicht ist er ja trotzdem noch aktuell für dich.

    Caipi



  • Mist, voll verlesen ... hattest es ja schon selber rausgefunde ... :p


Anmelden zum Antworten