Klassen in C++ Durchschnitt von zwei Zahlen berechnen
-
@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; }
-
@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, dassAverage
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 inget_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 aufprotected
.In Kurzform für C++: Es gibt eine Entkopplung in der API aber weiterhin Abhängigkeit in der ABI beim Verzicht auf
protected
.
-
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.
-
@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.
-
@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?
-
@SeppJ hat Recht: Durch protected erschafft man eine Abhaengigkeit zum (protected) Interface. Abhaengigkeiten zu Implementierungsdetails sind aber die #1 Motivation dafuer, ueberhaupt private zu haben. Deshalb ergibt protected i.d.R. nur bei Hilfsmembern Sinn.
@john-0 Wie viele Leute muessen Dir Deine perniziösen Verhaltensmuster noch psychoanalysieren, bevor Du mal anfaengst zu reflektieren? Unabhaengig davon, ob irgendwelche nuetzlichen Erkenntnisse in Deinen Posts enthalten sind: Jeder Thread mit Dir artet in eine passiv-aggressive Spirale von irrelevanten Seitenthemen aus, ohne am Ende noch Mehrwert zu bieten. Frag Dich mal, ob das Resultat mit Deinen (hoffentlich aufrichtigen) Intentionen übereinstimmt.
-
Es wird sich hier im Forum immer wieder geäußert, dass so wenige Nutzer sich länger im Forum engagieren. Dreimal darfst du raten, weshalb das der Fall ist. Glaubst du ernsthaft normale Menschen haben Lust auf diese fortgesetzte verbalen Entgleisungen(1) der Mods in diesem Forum?
(1) Dir fällt auch nichts besseres ein als im erstes Posting mir gleich ein krankhaftes Verhalten anzudichten.
Ich kenne so ein Verhalten nur aus dem Usenet, von einer bestimmten Person mit Kürzel Fefe. Aber Fefe war für sachliche Argumente zugänglich.
P.S. Wenn du mich nicht im Forum haben willst, schreib das einfach, anstatt mich jedesmal anzupöbeln.
-
@john-0 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:
länger im Forum engagieren...Glaubst du ernsthaft normale Menschen haben Lust auf diese fortgesetzte verbalen Entgleisungen(1) der Mods in diesem Forum?
Ich bin seit 2009 registriert und war davor schon ein paar Jahre nicht registriert unterwegs (ging damals noch). Ich kann mich an keine nenneswerte Entgleisung eines Mods erinnern.
@john-0 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:
Wenn du mich nicht im Forum haben willst, schreib das einfach, anstatt mich jedesmal anzupöbeln.
Wenn dich jemand nicht im Forum haben wollte, dann hätte sich @SeppJ wohl nicht extra die Mühe gemacht, mal zu schreiben, warum deine Antworten soooo anstrengend sind.
-
Was bin ich froh dass ich nur die Schatten dieser Diskussion sehe
-
Mich juckt das auch nicht. Habe zwar niemanden ignoriert, aber ich finde es gut, wenn es auch solche Diskussionen gibt. Je nach Kenntnis kann jeder sein eigenes Urteil bilden. Sehe hier auch nicht die Gefahr, das "Unwissende" gefährdet sein könnten.
-
@john-0 sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:
@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.Nein. Es geht hier darum, der Threaderstellerin zuerst die wichtigen Ratschläge zu geben. Und da gilt für, mich dass die ABI in diesem Stadium des Lernens gar keine Bedeutung hat und die API eine große Bedeutung hat. In einem anderen Leserkreis wäre deine Diskussion sicherlich relevant, aber in diesem Kontext ist sie nicht zielführend, da sie unter Umständen auch zur Verwirrung beiträgt.
-
@zeropage sagte in Klassen in C++ Durchschnitt von zwei Zahlen berechnen:
Mich juckt das auch nicht. Habe zwar niemanden ignoriert, aber ich finde es gut, wenn es auch solche Diskussionen gibt. Je nach Kenntnis kann jeder sein eigenes Urteil bilden. Sehe hier auch nicht die Gefahr, das "Unwissende" gefährdet sein könnten.
Das Urteil, das ich mir aus diesen Diskussionen gebildet habe, ist menschlich, nicht fachlich. Und SeppJ hat es schon ziemlich gut beschrieben.
Das sind so Diskussionen, auf die ich nicht wirklich Bock habe, weil sie zu 99,99% Dinge behandeln, die ich in meinen Quelltexten nicht habe. Und ich habe genug andere Dinge zu tun, um mich akademische Nischenprobleme zu kümmern.
-
Hallo, damit die Streitigkeiten mal ein Ende finden, ich wäre die Sache ungefähr so angegangen:
#include <iostream> using namespace std; class Average { private: const bool exact; int32_t count = 0; int64_t sum = 0; double avg = 0; public: Average(); Average(int32_t size); ~Average(); void addElement(int32_t e); double getAvg(); }; Average::Average() : exact(true) { } Average::Average(int32_t size) : exact(false), count(size) { } Average::~Average() { } void Average::addElement(int32_t e) { if (exact) { count++; sum += e; } else { avg += e / (double)count; } } double Average::getAvg() { if (exact) { return sum / (double)count; } else { return avg; } } int main(int argc, char const *argv[]) { Average a1; Average a2(3 * 10); int32_t vals[] = { -23, 456, -543}; for (size_t i = 0; i < 10; i++) { for (const auto &e : vals) { a1.addElement(e); a2.addElement(e); } } cout.precision(17); cout << a1.getAvg() << "\n"; cout << a2.getAvg() << "\n"; double expected = -36.666666666666666; cout << expected << "\n"; cout << abs(a1.getAvg() - expected) << "\n"; cout << abs(a2.getAvg() - expected) << "\n"; return 0; }
Ich denke, das ist so richtig... Die Ausgabe ist bei mir (bei euch hoffentlich auch...):
-36.666666666666664 -36.666666666666686 -36.666666666666664 0 2.1316282072803006e-14
(Falls ich was übersehen hab, bitte Hinweise geben Danke)
-
Mein Senf dazu:
using namespace ...
gehört nicht in Header Dateien- fehlende const-correctness
- Warum keine Default-Initialisierung für
exact
? - Warum ist
exact
const? Damit verhinderst du, dass Kopien erzeugt werden können, ist das so gewollt? Es ist privat und kann nur über den Konstruktor gesetzt werden, warum machst du das noch zusätzlich const? - C-style casts (Zeile 50) in C++ sind meh
-
Danke fürs Feedback/Review @DocShoe ...
Warum ich das mache? Weil ich es nicht besser wusste... Hast du einen Änderungsvorschlag? lg.