Style Frage, namespace und class
-
danke für Dein feedback. Nun, wer
std::
notiert kann auchthis->
notieren
Ne, im Ernst, ich meine das alles zusammen so:class BaseClass{ public: std::string name; std::string get_name(){ return this->name; }; }; class SubClass : public BaseClass{ public: // Eigenschaften der Instanz sind in der Basisklasse deklariert // Im Konstruktor der Unterklasse werden den Eigenschaften // die Werte zugewiesen SubClass(const std::string &name){ this->name = name; }; }; int main(){ SubClass so("Müller"); std::cout << so.get_name() << std::endl; return 0; }
Da der Construktor ohnehin nicht geerbt wird, kann man, sofern er über die Unterklasse nicht aufgerufen wird, auf die Deklaration verzichten. Geerbt werden wie gehabt, Eigenschaften (ohne Wert) und Methoden. Unter dessen übernimmt der Konstruktor der Subklasse die Wertzuweisung an die geerbten Eigenschaften.
Für mich klingt das alles schlüssig, es dient der Lesbarkeit und entspricht meinen Vorstellungen einer OOP.
Viele Grüße!
-
@_ro_ro
Würde ich nicht so machen.this
braucht man an den Stellen einfach nicht. Wenn man Variablen als Member kenntlich machen will, kann man einm_
vorstellen, oder ein_
nachstellen, aber alles mitthis
zu schreiben ist too much und unüblich.std::
schreibt man ja, weil es aus einem anderen Namespace kommt und man den nicht dauerhaft inkudieren möchte, damit man keine Probleme durch Namensdoppelungen bekommt.Initialisierung auch besser so:
SubClass(const std::string &name): name(name){};
Ist am Ende wieder der unterschied zwischen copy initialization und direct initialization.
Was ich auch schon gesehen habe, um die Unterschiede klar zu machen, wäre so was:
SubClass(const std::string &aName): name(aName){};
-
@_ro_ro sagte in Style Frage, namespace und class:
Da der Construktor ohnehin nicht geerbt wird, kann man, sofern er über die Unterklasse nicht aufgerufen wird, auf die Deklaration verzichten. Geerbt werden wie gehabt, Eigenschaften (ohne Wert) und Methoden. Unter dessen übernimmt der Konstruktor der Subklasse die Wertzuweisung an die geerbten Eigenschaften.
Meh, damit kann ich mich nicht anfreunden. Wenn der Konstruktor einen Parameter für das Attribut der Basisklasse hat, dann sollte der Konstruktor der Basisklasse diesen Parameter auch haben. Ich verwende mal deine Art Variablen zu benennen:
struct Base { std::string name Base( std::string const& name ) : name( name ) { } }; struct Super : Base { Super( std::string const& name ) : Base( name ) { } };
-
nun, in der Basisklasse sind die Attribute nur deklariert, das hat ja ersteinmal mit Vererbung nix zu tun. Wenn man diese Attribute jedoch erben will, also so daß da auch was drinsteht (!), muss man aus der Unterklasse heraus den Konstruktor der Baisklasse aufrufen und die Werte zur Initialisierung übergeben. Oder man initialisiert die Attribute eben nur in der SubClass ohne den Konstruktor der BaseClass zu bemühen.
Dieses Verhalten ist in Perl und in PHP übrigens ganz genauso.
Mit freundlichen Grüßen.
-
C++ ist weder Perl noch PHP. Wenn du Konzepte einer anderen Sprache 1:1 auf C++ überträgst lässt du vermutlich C++ Benefits liegen. Das ist in diesem Beispiel nicht nur eine Coding-Style Frage, sondern hat auch Auswirkungen auf die Performance.
class Base { private: std::string Name_; public: Base() = default; Base( std::string const& name ) : Name_( name ) { } std::string const& name() { return Name_; } //protected:? void set_name( std::string const& name ) { Name_ = name; } }; class Super : public Base { public: // Konstruktor 1 Super( std::string const& name ) : Base( name ) { } // Konstruktor 2 Super( std::string const& name ) { set_name( name ); } };
Konstruktor 1 hat Konstruktor 2 gegenüber den Vorteil, dass er mit weniger Kopien auskommt, weil
Name_
direkt initialisiert werden kann. Außerdem musst du immer einen Manipulator anbieten, selbst wennName_
Nur-Lesezugriff anbieten soll.
-
@DocShoe sagte in Style Frage, namespace und class:
sondern hat auch Auswirkungen auf die Performance.
Was genau hat jetzt Auswirkungen auf die Performance?
MFG
-
@_ro_ro sagte in Style Frage, namespace und class:
Was genau hat jetzt Auswirkungen auf die Performance?
Die Polymorphie und dynamische Bindung.
-
@_ro_ro Ich möchte anmerken, dass keine der Klassen in deinem wie auch dem von @DocShoe gezeigten Code eine polymorphe Klasse ist. Alle Argumente auf dieser Schiene sind dadurch hinfällig, auch wenn Polymorphie in anderem Kontext durchaus (oft aber nur geringfügig) performancerelevant sein kann.
Man sollte Versuche, diese Diskussion hier zu sabotieren besser ignorieren - auch wenn die für Einsteiger nicht immer leicht zu entlarven sind, da unser Troll seine Beiträge gerne in eine pseudo-kompetente Fassade kleidet. Ich empfehle "User blockieren", das spart eine Menge Ärger.
-
-
Versuche doch noch einmal, den Post von @DocShoe zu verstehen.
Vielleicht ist es wichtig zu verstehen, dass der Konstruktor zuerst alle Member-Variablen erstellt (und von allen nicht-POD-Membern den Konstruktor aufruft (in der Reihenfolge, wie sie in der Klasse deklariert sind) und erst danach den Code zwische den
{ ... }
ausführt.Ein
struct X { std::string s; X() { s = "Hallo"; } }; X x;
entspricht also ungefähr einem
string x_s; // leer initialisieren x_s = "Hallo"; // zuweisen
Wohingegen ein
struct Y { std::string s; Y() : s("Hallo") { }; }; Y y;
einem
std::string y_s("Hallo"); // direkt initialisieren
entspricht, also direkt initialisiert wird und nicht erst der parameterloste Konstruktor aufgerufen wird.
-
@Finnegan sagte in Style Frage, namespace und class:
@_ro_ro Ich möchte anmerken, dass keine der Klassen in deinem wie auch dem von @DocShoe gezeigten Code eine polymorphe Klasse ist. Alle Argumente auf dieser Schiene sind dadurch hinfällig, auch wenn Polymorphie in anderem Kontext durchaus (oft aber nur geringfügig) performancerelevant sein kann.
Man sollte Versuche, diese Diskussion hier zu sabotieren besser ignorieren - auch wenn die für Einsteiger nicht immer leicht zu entlarven sind, da unser Troll seine Beiträge gerne in eine pseudo-kompetente Fassade kleidet. Ich empfehle "User blockieren", das spart eine Menge Ärger.
Fragt sich nur, wer hier der größere Troll ist... Du oder @_ro_ro
Mal im Ernst, mit 70 ist man zu alt für die Softwareentwicklung.
-
@wob , danke, ja das erscheint mir schlüssig. Ich habe das schon in Perl vermieden, die Eigenschaften über den Aufruf des Konstruktors der Superklasse zu initialisieren. Viele Grüße!
-
@_ro_ro sagte in Style Frage, namespace und class:
Ich habe das schon in Perl vermieden, die Eigenschaften über den Aufruf des Konstruktors der Superklasse zu initialisieren.
Nur damit ich sicher bin, dass du es richtig verstanden hast: du sollst den Konstruktor der Superklasse verwenden! Aber eben mit dem Doppelpunkt direkt aufrufen. Also sowas wie
Derived::Derived(const type& variable): Base(variable), derived_member_variable(42), ... {}
- sonst hast du immer den Doppelschritt. Beachte außerdem, dass, anders als in Java zum Beispiel, im{...}
-Bereich des Base-Konstruktors der Typ noch Base ist, auch wenn du gerade ein Derived erzeugst. Also das Aufrufen einer virtuellen Funktion im Base-Konstruktor ruft noch nicht die derived Funktion auf.
-
@wob sagte in Style Frage, namespace und class:
Nur damit ich sicher bin, dass du es richtig verstanden hast: du sollst den Konstruktor der Superklasse verwenden!
Mit Doppelpunkt ist klar aber warum soll ich den Konstruktor der Superklasse überhaupt aufrufen wenn ich alle in der Superklasse deklarierten Eigenschaften im Konstruktor der Subklasse initialisieren kann? Der ~Destruktor der Superklasse wird doch in jedem Fall aufgerufen egal ob es einen Konstruktor gibt oder nicht.
Viele Grüße!
-
@_ro_ro Weil die private Member von Base in der Initialisierungsliste der Derived Klasse nicht zugreifbar sind (Kapselung) und wegen Wiederverwendbarkeit
class Base { public: Base(int a, int b): a(a), b(b) {} private: int a{}; int b{}; }; class Derived1 : public Base { public: Derived1 (int a, int b, int c): Base(a , b), c(c) {} private: int c{}; }; class Derived2 : public Base { public: Derived2 (int a, int b, double c): Base(a , b), c(c) {} private: double c{}; };
Das geht nicht:
class Derived1 : public Base { public: Derived1 (int a, int b, int c): c(c), a(a), // wir können hier auf a nicht zugreifen b(b) {} private: int c{}; };
-