Macht sowas Sinn? (Konstruktor)
-
Nexus schrieb:
~john schrieb:
Artikel (std::string const& name, int const nummer, double const preis) : name_ (name), nummer_ (nummer), preis_ (preis)Von dem
intstattlongeinmal abgesehen, wieso machst du die elementaren Parametertypen konstant?… , weil diese Variablen im Konstruktor nicht verändert werden sollen. Man kann es auch weglassen, aber die Macht der Gewohnheit. Nicht Referenzparameter mache ich meisten "const", weil man so dem Problem aus dem Weg geht, daß man aus Versehen ihnen was zuweist, was sich dann nicht auswirkt, da es ja Kopien sind.
-
Okay. Nun ja, ich mach sie meistens nicht
const, da man so Platz spart und man gleich schneller sieht, ob es sich um eine Const-Referenz handelt (das Zeichen & muss man zuerst suchen, um eine Referenz zu erkennen - je länger der Typbezeichner, desto mühsamer).
Aber ja, ist halt Geschmackssache. Mir ist kein Fall bekannt, bei dem ich eine Kopie verändert und gemeint habe, das Original werde manipuliert. Schon gar nicht bei einem Konstruktor...

-
In diesem Fall mußt Du entweder alle drei Parameter zur Verfügung stellen, oder gar keinen.
Das ist aber eine unnötige Belästigung und du musst auch den Konstruktor 2 mal schreiben. Und im Falle einer Änderung der Klasse das für alle Konstruktoren anpassen. Das ist doch unnötig umständlich, wenn man das einfach per Defaultwerte regeln kann. (man muss halt auf die Reihenfolge achten.)
-
drakon schrieb:
Das ist doch unnötig umständlich, wenn man das einfach per Defaultwerte regeln kann.
Da implementiere ich lieber zwei Mal den Konstruktor als dass nachher noch die Möglichkeit besteht, ein halbwegs gültiges Objekt zu erstellen, wenn nur einige der Argumente angegeben werden. Ein Artikel mit Namen und Nummer, aber ohne Preis macht nun mal nicht viel Sinn.
Ein Artikel ohne irgendwas im Übrigen auch nicht, hier wäre es vielleicht sogar am besten, keinen Standardkonstruktor zur Verfügung zu stellen (das kann einen halt ein wenig einschränken, aber es sollte schon gehen). So kann man sicherstellen, dass jede
Artikel-Instanz wirklich einen Artikel repräsentiert.
-
Ich glaube, es ging im ganz grundsätzlich darum, ob sowas geht und ob das Sinn macht. Wie man im ersten Post des TOs lesen kann, handelt es sich hier um etwas aus einem C++-Buch bzw. um eine Übung.
Ob dieses für das konkrete Beispiel aus Designsicht sinnvoll ist, sei mal dahingestellt.
Grundsätzlich ist das Zuweisen von Defaultwerten jedoch ein durchaus sinnvolles Feature, und Konstruktoren die mit Defaultwerten für jeden Parameter belegt sind, geben valide Defaultkonstruktoren.
-
Nexus schrieb:
drakon schrieb:
Das ist doch unnötig umständlich, wenn man das einfach per Defaultwerte regeln kann.
Da implementiere ich lieber zwei Mal den Konstruktor als dass nachher noch die Möglichkeit besteht, ein halbwegs gültiges Objekt zu erstellen, wenn nur einige der Argumente angegeben werden. Ein Artikel mit Namen und Nummer, aber ohne Preis macht nun mal nicht viel Sinn.
Ja. Hier macht es tatsächlich nicht viel Sinn, kann es aber an anderen Orten.
Z.B eine Kasse. Eine Kasste hat vlt. einen Namen, Maximalbetrag und einen Startbetrag (und ev. weitere Werte). Ich habe da keine Lust jedwede Kombination einen Konstruktor zu schreiben. (Vor allem, wenn es 4, oder noch mehr Werte sind).
Das ganze hat aber rein gar nichts zu tun, ob das Objekt gültig ist, oder nicht. Die Invarianz ist ebenso gegeben, wie, wenn du per Überladung machst.
Ob es logisch Sinn macht ist dann eine ganz andere Frage.
Im übrigen kannst du die Parameter auch erzwingen, wenn du willst, indem du die Reihenfolge änderst..
-
drakon schrieb:
In diesem Fall mußt Du entweder alle drei Parameter zur Verfügung stellen, oder gar keinen.
Das ist aber eine unnötige Belästigung und du musst auch den Konstruktor 2 mal schreiben.
Default Werte sind schlecht, aber das schrieb ich bereits.
Beispiel warum das so ist. Faulheit war schon immer der Weg zu schlechtem Code.#include <string> using namespace std; class Artikel { string name; long nummer; double preis; public: Artikel(string const& k_name = "Kein Eintrag", long k_nummer = 0, double k_preis = 0.0) { name = k_name; nummer = k_nummer; preis = k_preis; } }; int main () { string s = "Defaultwerte sind schlecht!"; Artikel a1; Artikel a2 = s; // Konversion! a1 = s; // Konversion! }
-
~john schrieb:
Beispiel warum das so ist. Faulheit war schon immer der Weg zu schlechtem Code.
dann wird der Konstruktor halt explizit und der Zuweisungsoperator implementiert
im vorliegenden Fall wuerde ich aber die Artikelbezeichnung als verpflichtenden Parameter definieren... und die Artikelnummer je nach Anforderung auch... der Preis kann ruhig optional sein
-
Tachyon schrieb:
Grundsätzlich ist das Zuweisen von Defaultwerten jedoch ein durchaus sinnvolles Feature, und Konstruktoren die mit Defaultwerten für jeden Parameter belegt sind, geben valide Defaultkonstruktoren.
Das ist der beste Weg sich selbst ein Bei zu stellen. Wenn man das überhaupt macht, dann bitte schon als "explicit" Konstruktor. Andernfalls hat man sich ganz schnell einen Konversionskonstruktor geschaffen, den man möglicherweise gar nicht will.
-
zwutz schrieb:
dann wird der Konstruktor halt explizit und der Zuweisungsoperator implementiert
Der Zuweisungsoperator ist überflüssig, er verhindert eine Konversion nicht.
-
~john schrieb:
Tachyon schrieb:
Grundsätzlich ist das Zuweisen von Defaultwerten jedoch ein durchaus sinnvolles Feature, und Konstruktoren die mit Defaultwerten für jeden Parameter belegt sind, geben valide Defaultkonstruktoren.
Das ist der beste Weg sich selbst ein Bei zu stellen. Wenn man das überhaupt macht, dann bitte schon als "explicit" Konstruktor. Andernfalls hat man sich ganz schnell einen Konversionskonstruktor geschaffen, den man möglicherweise gar nicht will.
Nichts für ungut, aber das ist Bullshit
Wenn man mehrere Ctors überlädt, dann hat man ebenfalls irgendwelche mehr oder weniger sinnvollen Defaultwerte im Objekt drin. Ob die nun über Defaultparameter direkt kommen, oder von zig unterschiedlichen Ctors erzeugt werden, ist völlig irrelevant.
Außerdem sagte ich bereits, dass man sich, um den Sinn oder Unsinn von Defaultwerten bewerten zu können, vielleicht nicht unbedingt an diesem Beispiel aufhängen sollte.PS: Schau Dir mal die Ctors aus der STL an. Da wirst Du viele Beispiele für sinnvolle Defaultparameter finden.
-
Beispiel warum das so ist. Faulheit war schon immer der Weg zu schlechtem Code.
Faulheit ja. Aber man muss sich ja auch nicht die unnötige Mühe machen und doppelten Code schreiben.
Oder verzichtest du auch auf Templates und schreibst dir jede mögliche Klasse selbst?
Ein (unnötiger) doppelter Konstruktor ist imo fehleranfälliger und gefährlicher, da sich der allfällig vergessene explicite Konstruktor nur in "fehlerhaften" Anwendungscode auswirkt, wobei ein falsch implementierter Konstruktor in Anwendungscode nicht gefunden werden kann.Was der Zuweisungsoperator jetzt hier zu suchen hat, entzieht sich meiner Vorstellung.
-
Ob man nur den einen Konstruktor mit Default-Parametern nutzt oder zwei (parameterloser Konstruktor und volle Initialisierung), sollte imho eher vom Anwendungsfall abhängig gemacht werden. Mit dem Default-Parameter-Konstruktor handelt man sich de facto vier Konstruktoren ein, wenn jeder davon sinnvoll ist, haben wir doch unseren Kandidaten.
Es heißt doch, Klassen sollen nur schwer "falsch" zu benutzen sein. Wenn das hierArtikel[] artikel = { Artikel("Apfel"), Artikel("Birne") };im Sinne der Anwendung ok ist, ist's super. Aber bitte nicht den Konstruktor mit Default-Parametern anbieten und in der Doku sowas schreiben: "Hier entweder keinen oder alle Parameter angeben!".