Klassen in C++ Durchschnitt von zwei Zahlen berechnen



  • Hallo,

    ich versuche gerade das Thema Klassen in C++ besser zu verstehen. Ich möchter gerne von zwei Zahlen den Durchschnitt berechnen. Dazu möchte ich gerne eine Klasse Average verweden. Problem, wenn ich meinen Code ausführe kommt ein sehr kleiner Wert heraus. Hier mein Code:
    Danke für einen Tipp

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    using namespace std;
    
    
    class Average{
    
    private:
        double _avg;
        double _sum;
        int _count;
    
    public:
        void add(double val){
                 _sum += val;
                 _count++;
                 _avg = _sum / _count;
        }
    
        double get_avg(){return _avg;}
    
    };
    
    int main(){
    
        Average a;  // Standardkonstruktor
        a.add(12.4);
        a.add(23.7);
    
        cout << a.get_avg() << endl;
    
    
        return 0;
    
    }
    
    


  • @jasmin89 Hi, du musst deine Membervariablen initialisieren, sonst können die einen beliebigen Wert am Anfang haben.



  • Stimmt, danke für den Tipp



  • Ich habe nun meine Klasse mit einer Abgeleiteten Klasse erweitert. Die sollte das Ergebniss von Average übernehmen und es quadrieren. Nur kommt bei mir nun der Fehler dass _avg private ist. Kann ich den Wert nicht einfach in der abgeleiteten Klasse übernehmen?

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    using namespace std;
    
    
    class Average{
    
    private:
        double _avg=0;
        double _sum=0;
        int _count=0;
    
    public:
        void add(double val){
                 _sum += val; // sum =sum + val
                 _count++;
                 _avg = _sum / _count;
        }
    
        double get_avg(){return _avg;}
    
    };
    
    
    class Abgeleitet : public Average{
    
        private: double _qdr=0;
    
        public:
            void quadrieren(double get_avg()){
                 _qdr= _avg * _avg;
        }
    
        double get_qdr(){return _qdr;}
    
    
    
        };
    
    int main(){
    
        Average a;  // Standardkonstruktor
        Abgeleitet b;
    
        a.add(12.4);
        a.add(23.7);
    
    
        cout << a.get_avg() << endl;
        cout << b.get_qdr() << endl;
    
    
        return 0;
    
    }
    
    

  • Mod

    @jasmin89 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Kann ich den Wert nicht einfach in der abgeleiteten Klasse übernehmen?

    Genau das sagt private aus. Das ist auch gut so, denn welchen Grund hast du an den Innereien deiner Elternklasse herumzuspielen? Sie bietet doch sogar kontrollierten Zugriff auf den Durchschnitt als Teil ihrer öffentlichen Schnittstelle an. Benutz den!

    Wenn es Ziel ist, dich mit Klassen näher zu beschäftigen, dann sind die Zugriffsspezifizierer ein wichtiges Thema.



  • @jasmin89 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    public:
    void quadrieren(double get_avg()){
    _qdr= _avg * _avg;
    }

    Kannst du erklären, was du hier vor hast: void quadrieren(double get_avg())? Mir geht es insbesondere um den Teil in der Klammer.



  • @SeppJ: Danke. Ich habe mir ja die Memberfunktion get_avg() definiert um diese Schnittstelle nach außen von _avg zu haben. Ich kann diese auch in der Konsole ausgeben. Aber wie kann ich das Ergebnis der Funktion get_avg() auch in der abgeleiteten Klasse verwenden? Müsste ich nicht Zugriff auf das Ergebnis von get_avg() in der Abgeleiteten Klasse haben? Denn ich bekomme es nicht hin genau dieses Ergebnis in der Klasse Abgeleitet zu verwenden.



  • @jasmin89 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Müsste ich nicht Zugriff auf das Ergebnis von get_avg() in der Abgeleiteten Klasse haben?

    Du hast in der abgeleiteten Funktion Zugriff auf die Funktion get_avg(). Was meinst du mit dem Zusatz "das Ergebnis von"?

    Ich finde es allerdings etwas fragwürdig, dass die den Durchschnitt als Membervariable hast (und das nun auch mit dem Quadrat versuchst). Du müsstest dann das add überschreiben, um auch das Quadrat zu aktualisieren. Besser wäre vermutlich, wenn du den Durschnitt immer on-the-fly berechnest. Dann kannst du auch das Quadrat immer on-the-fly berechnen.

    Ich frage mich aber auch, wozu du hier überhaupt eine Klassenhierachie brachst.



  • @jasmin89 3 Sachen stimmen meiner Meinung nach noch nicht.

    1. Statt private musst du protected, in der Klasse Average, verwenden, damit die Kindklasse die Variablen und Funktionen sieht und sie dennoch außerhalb deiner Klasse unsichtbar sind.
    2. Du kannst der Funktion quadrieren() nicht get_avg() übergeben und hoffen dass der Wert da schon irgendwie rauspurzelt. Du kannst jedoch in quadieren() get_avg() aufrufen.
    3. In der main() hast du 2 verschiedene Objekte a und b. Wenn du a Werte zuweist, hat b trotzdem noch keine Werte erhalten. Genauso wäre es ja auch mit 2 Objekten der selben Klasse.
    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    using namespace std;
    
    class Average{
    
    protected:
        double _avg=0;
        double _sum=0;
        int _count=0;
    
    public:
        void add(double val){
                 _sum += val; // sum =sum + val
                 _count++;
                 _avg = _sum / _count;
        }
    
        double get_avg(){return _avg;}
    };
    
    class Abgeleitet : public Average{
    
        private: double _qdr=0;
    
        public:
            void quadrieren(){
                 a = get_avg();
                 _qdr= a * a;
        }
    
        double get_qdr(){return _qdr;}
        };
    
    int main(){
    
        Average a;  // Standardkonstruktor
        a.add(12.4);
        a.add(23.7);
        cout << a.get_avg() << endl;
    
        Abgeleitet b;
        b.add(12.4);
        b.add(23.7);
        cout << b.get_qdr() << endl;
    
        return 0;
    }
    

    Für den Code übernehme ich keine Garantie, den hab ich live in den Browser getippt.



  • @shokwave sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Statt private musst du protected, in der Klasse Average, verwenden, damit die Kindklasse die Variablen und Funktionen sieht und sie dennoch außerhalb deiner Klasse unsichtbar sind.

    Und warum genau soll die abgeleitete Klasse die member Variablen von Average kennen? Genau dafür gibt es doch den Getter.



  • @Schlangenmensch sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Und warum genau soll die abgeleitete Klasse die member Variablen von Average kennen? Genau dafür gibt es doch den Getter.

    Du hast natürlich Recht, die braucht man, wenn man den Getter benutzt nicht mehr. Da hätte ich besser schreiben sollen entweder get_avg() benutzen oder die Variablen protected machen.

    Ich hab den Code nochmal überarbeitet, weil er so nicht lauffähig war.

    #include <iostream>
    
    using namespace std;
    
    class Average {
    
    private:
        double _sum=0;
        int _count=0;
    
    public:
        void add(double val) {
             _sum += val; // sum = sum + val
             _count++;
        }
    
        double get_avg() {
    		return _sum / _count;
    	}
    };
    
    class Abgeleitet : public Average{
    
    public:
        double get_qdr() {
             double a = get_avg();
             return a * a;
    	}
    };
    
    int main() {
    
        Average a;  // Standardkonstruktor
        a.add(18.7);
        a.add(19.6);
        cout << "Average von a = " << a.get_avg() << endl;
    
        Abgeleitet b;
        b.add(12.4);
        b.add(23.7);
        cout << "Average von b = " << b.get_avg() << endl;
        cout << "Quadrat von b = " << b.get_qdr() << endl;
    
        return 0;
    }
    

  • Mod

    @shokwave sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Da hätte ich besser schreiben sollen entweder get_avg() benutzen oder die Variablen protected machen.

    Nein, bitte gar nicht protected benutzen hier! Dies wäre das perfekte Beispiel wenn ich irgendwann mal einen Artikel "Protected considered harmful" schreiben sollte.

    Wenn man protected nutzt, koppelt man diese Teile der Implementierung der Elternklasse fest an die Kinderklassen. Das will man im Allgemeinen¹ nicht! Dann sind diese Teil der öffentlichen(! Denn jeder kann von uns erben!) Schnittstelle der Klasse und müssen entsprechend respektiert werden. In diesem Falle hieße das, dass Average stets dafür zu sorgen hätte, dass der Wert in _avg aktuell und konsistent ist. Man kann also niemals von der hier anfangs vorgeschlagenen Implementierung weg (oder muss sie stets zusätzlich mit herumschleppen), obwohl eine der ersten Reaktionen auf diese Implementierung direkt war, dass es eigentlich gar keinen Sinn macht, diesen Zwischenwert ständig neu abzuspeichern, sondern man den Wert besser nur bei Bedarf in get_avg berechnen könnte. Wie du es ja auch selber vormachst.

    Jedenfalls sollte man niemals Implementierungsdetails einer Klasse zum Teil der öffentlichen Schnittstelle machen, und protected ist Teil der öffentlichen Schnittstelle.

    ¹: Irgendwo gab's hier im Forum schon einmal eine Diskussion, wann man es doch wollen könnte. Aber sagen wir es so: Wenn es gerechtfertigt ist, dann weiß man es auch, weil man gute Designgründe hat. "Ich möchte aber darauf zugreifen können!" ist kein guter Grund.



  • @SeppJ Danke für die Klarstellung. So hatte ich das noch nicht gesehen, aber es macht natürlich alles Sinn was du schreibst.



  • @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Wenn man protected nutzt, koppelt man diese Teile der Implementierung der Elternklasse fest an die Kinderklassen.

    Das tut man in C++ immer, da jede Änderung der Elternklasse die ABI bricht, vollkommen unabhängig davon ob man Getter oder protected nutzt. Getter haben in C++ geringere Vorteile, in anderen Sprachen sieht die Sache anders aus, da bekommt man eine komplette Entkopplung mit dem Verzicht auf protected.

    In Kurzform für C++: Es gibt eine Entkopplung in der API aber weiterhin Abhängigkeit in der ABI beim Verzicht auf protected.


  • Mod

    Und ABIs interessieren bei Designfragen inwiefern? Typischer Beitrag von dir, völlig nutzlos, nur um irgendwas vermeintlich klug klingendes zu sagen.



  • @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Und ABIs interessieren bei Designfragen inwiefern?

    Kommt drauf an ob man ne lib oder ne Anwendung macht.


  • Mod

    @Tyrdal sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Und ABIs interessieren bei Designfragen inwiefern?

    Kommt drauf an ob man ne lib oder ne Anwendung macht.

    Was soll das ändern an der Designfrage, was Teil einer öffentlichen Schnittstelle sein sollte und was nicht? Nichts. Du darfst intern deine Klasse gerne PIMPLn, wenn dich stört, dass man abhängige Dinge neu compilieren muss, wenn man irgendwo etwas ändert. Eine Designfrage ist, wie man vermeidet, dass man abhängige Dinge neu programmieren muss, wenn man irgendwo etwas ändert.



  • @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Und ABIs interessieren bei Designfragen inwiefern? Typischer Beitrag von dir, völlig nutzlos, nur um irgendwas vermeintlich klug klingendes zu sagen.

    Das ist wieder eine typische Antwort von Dir, 90% verstanden und an den restlichen 10% scheiterst Du kläglich.

    Die ABI Änderungen, die sich durch Codeänderungen ergeben, erzwingen z.B. für Libraries ein anderes Design. Du willst mir doch nicht ernsthaft erzählen wollen, dass bei Qt o.ä. man bei einem Minor Release die ABI zerbrechen kann, und die Kunden das toll finden? Dieser Umstand ist Design relevant und das sollte ein jeder wissen und anwenden können.


  • Mod

    @john-0 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    Und ABIs interessieren bei Designfragen inwiefern? Typischer Beitrag von dir, völlig nutzlos, nur um irgendwas vermeintlich klug klingendes zu sagen.

    Das ist wieder eine typische Antwort von Dir, 90% verstanden und an den restlichen 10% scheiterst Du kläglich.

    Die ABI Änderungen, die sich durch Codeänderungen ergeben, erzwingen z.B. für Libraries ein anderes Design. Du willst mir doch nicht ernsthaft erzählen wollen, dass bei Qt o.ä. man bei einem Minor Release die ABI zerbrechen kann, und die Kunden das toll finden? Dieser Umstand ist Design relevant und das sollte ein jeder wissen und anwenden können.

    Es geht nicht darum, ob das falsch oder richtig ist, sondern dass das absolut gar nichts mit dem Thema zu tun hat. Du kommst in jeden Thread rein, konstruierst einen Strohmann, der so weit weg geholt ist, dass ganze Astrobiologielehrstühle sich nur damit beschäftigen, und greifst diesen dann an, um dich irgendwie toll zu fühlen, weil du eine Diskussion gewinnst, die aber nur in deinem eigenen Kopf existiert. Sieht man auch wieder toll an deiner Antwort hier, die überhaupt nicht auf irgendetwas eingeht, sondern mir irgendetwas zu Qt in den Mund legen möchte, das du dir wieder zwecks Selbstdarstellung ausgedacht hast. Hat schon seinen Grund, warum so viele der längerfristigen Mitglieder dieses Forums dich auf ihrer Ignoreliste haben. Aber uns Moderatoren nervt es halt einfach nur, und du hilfst halt auch niemandem damit, was eigentlich der Hauptzweck dieses Forums ist. Wahrscheinlich denkst du sogar wirklich, dass andere irgendwie beeindruckt wären von deiner scharfsinnigen Logik und schlagenden Argumenten, wenn sie nichts mehr erwidern, obwohl sie bloß genervt die Augen verdrehen und die durchsichtige Strohmanndiskussion ignorieren.



  • @SeppJ sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:

    sondern dass das absolut gar nichts mit dem Thema zu tun hat.

    Es geht um das Thema: Wie beeinflusst protected das Design von Klassen in C++. Das Design von C++ Klassen wird eben nicht nur von der API sondern auch von der ABI beeinflusst. Das könnte man nun akzeptieren, und als Ergänzung zu dem schon Geschriebenem akzeptieren. Dir fällt nichts besser ein zu wiederholten Mal eine Metadiskussion zu starten. Weshalb fällt es dir so schwer persönliche Angriffe zu unterlassen?


Anmelden zum Antworten