Style Frage, namespace und class



  • @_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 )
       {
       }
    };
    


  • @DocShoe

    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 wenn Name_ 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


  • Gesperrt

    @_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.



  • @Finnegan

    keen Problem, hab längst kapiert wo's hier lang geht 😉

    Schönen Abend!



  • 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.


  • Gesperrt

    @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{};
    };
    


  • @Schlangenmensch

    aaach die Privaten 😉 An die habch gar nicht gedacht. Jetzt klar alles danke!!!!

    MFG


Anmelden zum Antworten