Compiler findet Ctor nicht



  • CtorGesucht schrieb:

    Ich habe doch gesagt, dass ich alles umbenannt habe. Geht übrigens ganz einfach mit Suchen/Ersetzen. Postet ihr einfach 1:1 Code aus der Arbeit? Eher ungern.

    Sry, ich find es geil 😃 Versuch geglückt - poste am Schluss einen Kommentar mit einem Schuss Boshaftigkeit, und der ganze Rest des Beitrags wird ignoriert. Wie war das in dem anderen Post mit Berechenbarkeit?

    Um auf das Thema zurück zu kommen: Du wendest Suchen/Ersetzen auf Firmencode an?



  • Nick Unbekannt schrieb:

    Dann hast du ja schon festgestellt, dass du eigentlich eine const-Referenz willst und damit würde dein Code ein Fehler produzieren.

    ne, du hast ihn falsch verstanden. Er geht dabei Variablen ein, deren Veränderung ein internes Update der Datenstruktur nach sich ziehen.

    So kannst du eine Überprüfung zur Laufzeit machen, ob der Wert Sinn macht. Bekommst aber nicht mehr mit wer auf das Objekt zugreift. Selbst wenn du so fancy Dinge wie RTTI nutzt.

    Ähh ja? Brauchtest du unbedingt ein Argument?

    Das wird doch mit keinem(!) Punkt besser, wenn du einen setter verwendest. solange die Funktion public ist, kann sie jeder aufrufen. Fertig.

    Nebenbei kannst du sowohl eine const als auch eine non-const Version haben. Das erwähne ich nur, weil ich das Gefühl habe, dass du das nicht weißt.

    Fazit: ich finde den genannten Code sexy. Mir ist es manchmal egal, ob ich Interna einer Klasse offenlege, vor allem wenn es offensichtlich ist. Softwaretechniker finden es andersrum sicher besser, aber die müssen auch nicht den Code ertragen.

    Vgl:

    a.foo()+=1;
    a.setFoo(a.getFoo()+1);
    


  • otze schrieb:

    ne, du hast ihn falsch verstanden. Er geht dabei Variablen ein, deren Veränderung ein internes Update der Datenstruktur nach sich ziehen.

    Dann hat er den Fragesteller falsch verstanden. Wobei ich schon interessant finde, dass er Aufgrund der Konstruktor-Beschreibung Design-Fehler erkennen kann.

    otze schrieb:

    Das wird doch mit keinem(!) Punkt besser, wenn du einen setter verwendest. solange die Funktion public ist, kann sie jeder aufrufen. Fertig.

    Der Punkt ist, dass du überhaupt gar keinen Setter benötigst. Welchen Sinn hat es Parameter, die schon von Anfang der Lebenszeit des Objektes benötigt werden, erst später über Setter hinzuzufügen? Womöglich werden sie im nachhinein noch nicht mal mehr geändert. Dafür sind Konstruktoren gedacht und das war der Punkt.

    otze schrieb:

    Nebenbei kannst du sowohl eine const als auch eine non-const Version haben. Das erwähne ich nur, weil ich das Gefühl habe, dass du das nicht weißt.

    Und wo genau liegt da der Unterschied zu einer nur non-const Version? Der Compiler kann nicht mehr optimieren, darum ging es aber nicht, es ging um die Sichtbarkeit der Member.
    Btw. kannst du den Member dann auch gleich public machen, macht keinen Unterschied und der Compiler kann optimieren.

    Warum mir auch so eine Referenz nicht gefällt ist, dass du dir einfach die Referenz merken kannst und damit plötzlich den Member losgelöst von der Klasse behandeln kannst, obwohl er immer noch Member der Klasse ist. Wäre das vom Design so gedacht gewesen, hättest du wieder zu public greifen können. Das wäre dann wirklich offensichtlich.



  • Mit Compileroptimeirungen hat const nur wenig zu tun
    http://gotw.ca/gotw/081.htm

    Und die Technik, eine nicht konstante Referenz auf Interna zurückzugeben, grundsätzlich als schlecht zu bezeichnen ist auch blödsinn. So gut wie jede STL Klasse macht das z.B. so. Und es ist natürlich in jedem Fall besser als das betroffene Datenelement öffentlich zu machen.
    http://gotw.ca/gotw/070.htm



  • brotbernd schrieb:

    Und die Technik, eine nicht konstante Referenz auf Interna zurückzugeben, grundsätzlich als schlecht zu bezeichnen ist auch blödsinn.

    Habe ich auch nie behauptet. Das es für etwas nur den einen wahren Weg gibt, dass hat SchlechterCodeGefunden eingeführt.

    brotbernd schrieb:

    So gut wie jede STL Klasse macht das z.B. so.

    Es ist auch nichts dagegen einzuwenden, wenn es Sinn ergibt. Und bei string oder vector zum Beispiel macht es sehr viel Sinn.

    brotbernd schrieb:

    Und es ist natürlich in jedem Fall besser als das betroffene Datenelement öffentlich zu machen.

    Ohne dein Link gelesen zu haben, warum sollte es besser sein einen Funktionsaufruf zu machen, als den Member selber abzugreifen? Durch Inlining kann der Compiler den Funktionsaufruf zwar wegoptimieren, aber was hast du damit gekonnt? Eigentlich überhaupt nichts, weil es passiert genau das selbe. Auch die Sichtbarkeit hat in dem Moment den gleichen Status. Einziger Unterschied, du büßt die von otze geforderte Offensichtlichkeit ein.

    Allerdings hat das auch alles gar nichts mit der Ausgangsfrage zu tun, wie man ein Objekt zur Erstellung richtig parametrisiert.



  • Ohne dein Link gelesen zu haben, warum sollte es besser sein einen Funktionsaufruf zu machen, als den Member selber abzugreifen?

    🙄
    Lies doch einfach den Link...

    Herb Sutter schrieb:

    Now let's prove the "member data should always be private" guideline by assuming the opposite (that public/protect member data can be appropriate) and showing that in every such case the data should not in fact be public/protected at all.

    // Example 2(a): Nonprivate data (evil)
        //
        class X
        {
          // ...
        public:
          T1 t1_;
        protected:
          T2 t2_;
        };
    

    First, we note that this can always be transformed, without loss of either generality or efficiency, to:

    // Example 2(b): Encapsulated data (good)
        //
        class X
        {
          // ...
        public:
          T1& UseT1() { return t1_; }
        protected:
          T2& UseT2() { return t2_; }
        private:
          T1 t1_;
          T2 t2_;
        };
    

    Therefore even if there's a reason to allow direct access to t1_ or t2_, there exists a simple transformation that causes the access to be performed through a(n initially inline) member function. Examples 2(a) and 2(b) are equivalent. But is there any benefit to using the method in Example 2(a)?

    To prove that Example 2(a) should never be used, all that remains is to show that that:

    1. Example 2(a) has no advantages not present in Example 2(b);

    2. Example 2(b) has concrete advantages; and

    3. Example 2(b) costs nothing.

    Taking them in reverse order:

    Point 3 is trivial to show. The inline function, which returns by reference and hence incurs no copying cost, will probably be optimized away entirely by the compiler.

    Point 2 is easy: Just look at the source dependencies. In Example 2(a), all calling code that uses t1_ and/or t2_ mentions them explicitly by name; in Example 2(b), all calling code that uses t1_ or t2_ mentions only the names of the functions UseT1() and UseT2(). Example 2(a) is rigid, because any change to t1_ or t2_ (e.g., removing them and replacing them with something else, or just tacking on some instrumentation) requires all calling code to be changed to suit. In Example 2(b), however, instrumentation can be added, and t1_ and/or t2_ can even be removed entirely, without any change to calling code, because the member function completes the class's interface and "surrounds," "seals," and "protects" the internals.

    Zum Monsterkonstruktor vom Threadstarter:
    Für meinen Geschmack ist der auch etwas zu lang geraten - häufig ist das ein Hinweis auf ein suboptimales Klassendesign. Ein weiterer Hinweis ist, dass es für alles Default-Werte gibt. Evtl. kannst du das Design entschlacken, wenn du ein paar spezialisiertere Klassen einführst, die wirklich nur eine Aufgabe haben.



  • Und weiter? Die angeführten Vorteile sind doch arg an den Haaren herbeigezogen. Wenn ich den Getter als simple Durchreichefunktion ausgebe, dann ist die Bindung an das Attribut so eng, dass ich da nicht einfach etwas ändern kann. Der Datentyp muss erhalten bleiben, erst recht bei einer Referenz. Und für die Offensichtlichkeit, da haben wir es schon wieder, sollte sich auch der Name nicht allzu weit entfernen. Member x in y umzubennen und weiterhin über getx() auf ihn zuzugreifen ergibt wenig Sinn. Und leere Getter aus Kompatibilitäts-Gründen bereit zu stellen, halte ich doch für arg fragwürdig. In der Regel bezweckt man mit der Anforderung eines Wertes etwas. Und damit das noch ordnungsgemäß funktioniert ist es gar nicht so verkehrt den Code an das neue Klassendesign anpassen zu müssen.



  • Es geht einfach um die Trennung von Interface und Implementation. Das ist DAS Grundlegende Konzept der Objektorientierung.

    Wenn ich den Getter als simple Durchreichefunktion ausgebe, dann ist die Bindung an das Attribut so eng, dass ich da nicht einfach etwas ändern kann.

    Du programmierst aber nicht nur für den Augenblick, sondern möchtest evtl. später noch etwas verändern. Dann ist der Getter plötzlich keine simple Durchreichefunktion mehr. Davon muss der Benutzer deiner Klasse aber nichts wissen, d.h. er ruft einfach immer noch getX() auf und damit hat es sich.
    Das geht mit öffentlichen Attributen nicht.

    Die angeführten Vorteile sind doch arg an den Haaren herbeigezogen.

    Nein, sie beruhen auf langer Erfahrung und Logik.



  • LesenBildet schrieb:

    Dann ist der Getter plötzlich keine simple Durchreichefunktion mehr.

    Das Argument könnte man zählen lassen. Nur war hier von Änderungen im Typ und Namen des Members die Rede und nicht vom Zugriff auf den Member. Das Problem wirst du mit der Methode nicht umgehen können. Du kannst natürlich dir x mit getY() holen, aber das ist doch kein schönes Design die Bezeichner bis zur völligen Verwirrung wiederzuverwenden, nur aus Legacy-Gründen?

    LesenBildet schrieb:

    Die angeführten Vorteile sind doch arg an den Haaren herbeigezogen.

    Nein, sie beruhen auf langer Erfahrung und Logik.

    Es geht mir nicht darum Getter als Unsinn abzuwerten. Nur kann ich keinen Mehrwert erkennen, wenn ich einfach nur ein return im Getter mach und eine non-const-Referenz zurück gebe. Und was das lesen bildet betrifft, in dem Artikel wird diese Ansicht geteilt. Es wird aber darauf hingewiesen und jetzt kommen wir zu deinem Punkt, dass man vielleicht später in den Getter noch Funktionalität einbauen möchte. Vor Anpassungen wegen eines geänderten Typen kann mich diese Vorgehensweise aber nicht bewahren, wahrscheinlich wäre da ein direkter Member-Zugriff sogar sinnvoller.



  • Der Punkt ist, dass der Aufrufer immer noch nicht weiß, wie mein internes Datenformat aussieht.

    Ich kann zum Beispiel sowas machen:

    class Foo{
    private: 
      double x,y,z;
    public:
        double& getX(){return x};
        double& getY(){return y};
        double& getZ(){return z};
    };
    

    Ich kann mir auch später sagen: ne, nen Vektor so darzustellen ist vielleicht doch nicht so gut. Vielleicht sollte ich intern doch was besseres verwenden.

    kein Problem:

    class Foo{
    private: 
      MyVector vec;
    public:
        double& getX(){return vec[0]};
        double& getY(){return vec[1]};
        double& getZ(){return vec[2]};
    };
    

    Point proved.

    //edit
    sowas mache ich übrigens die ganze Zeit. Ein Getter nach obigem Schema erlaubt Restriktionen des Zugriffs auf die internen Daten. So kann ich im Beispiel oben absolute Kontrolle über die Positionsdaten gewähren, ohne die Kontrolle über die Größe des Vektors (zum Beispiel) zu verlieren.



  • Und wenn du jetzt schon festgestellt hast, dass dein Foo nicht die einzelnen Komponenten des Vectors kennen muss, warum muss es dann wissen, wie man auf sie zugreift? Konsequenterweise müsste dein getX bis getZ in den Vector wandern und du den Vector zurück geben. Das würde zwar den Designvorteil, den du dir hier ermogeln wolltest vernichten, aber wäre dann echte Objektorientierung.



  • Und was das lesen bildet betrifft

    Bitte nicht zu ernst nehmen. 🤡
    Ich hatte mich so genannt, weil deine Fragen exakt so im Link beantwortet wurden - mehr nicht. Inzwischen nenne ich mich nur noch so, damit man erkennt, dass hier immer der gleiche antwortet.

    Konsequenterweise müsste dein getX bis getZ in den Vector wandern und du den Vector zurück geben.

    Nein, müsste es nicht, da es den Benutzer meiner Klasse gar nicht zu interessieren hat, in welcher Dateistruktur die Daten vorliegen. Es kann dem User doch egal sein, ob die einzelnen Koordinaten (um beim x-y-z Beispiel zu bleiben) in einem std::vector, std::array oder als einzelne Werte gespeichert sind.
    Und genau deswegen schreibt man solche "trivialen" Getter und Setter, damit man flexibel bleiben kann.



  • Nick Unbekannt schrieb:

    Das würde zwar den Designvorteil, den du dir hier ermogeln wolltest vernichten, aber wäre dann echte Objektorientierung.

    Wie kommst du darauf? Den Benutzer von Foo soll es ja eben nicht interessieren, wie die Klasse innen funktioniert. DAS ist Objektorientierung...



  • Dann ist das ein schlechtes Beispiel, weil es hier offensichtlich ist, dass es sich um ein zusammengehöriges Objekt handelt. Anders lässt sich auch nicht begründen, warum man es intern als einzelnes Objekt handhaben will. Warum sollte ich aber als Nutzer wenn ich die X-Komponente des Vektors haben will, nicht den Vektor anfordern? Erstens muss Foo so nicht wissen, wie ein Vektor ist und zweitens kann ich so weiter im Kontext des Vektors verfahren. Dazu muss ich auch nicht wissen, ob Vektor ein std::vector oder std::array ist, da wir da ja wieder bei der Kapselung angelangt sind.
    In der Praxis würde ich die alten Getter auch stehen lassen. Dass wäre aber ein Punkt, wo ich in Java deprecated über die Methode schreiben würde.



  • @otze: Das ist kein getter. Das ist ein getter und setter in einem und das finde ich sau mies.
    Was ist z.B., wenn du im Getter nur einen gecachten Wert liefern willst, aber im setter() Checks durchführen willst, die nur bei Erfolg in den Cache schreiben? Da klappt dein Ansatz schon mal nicht. Dann hättest du Klassen mit den üblichen getter/setter und ein paar Klassen mit diesen Hybrid getter/setter und kein konsistentes System mehr => hässlich.

    Abgesehen davon ist es einfach syntaktisch hässlich. Oder willst du mir sagen, dass du solche Konstrukte schön findest?

    foo.bar() = foo2.bar();
    foo.bar()+=foo2.bar();
    

    Igitt. 👎



  • Anmerker2 schrieb:

    Oder willst du mir sagen, dass du solche Konstrukte schön findest?

    Ja findet er.

    http://www.c-plusplus.net/forum/p1992298#1992298



  • Warum sollte ich aber als Nutzer wenn ich die X-Komponente des Vektors haben will, nicht den Vektor anfordern?

    Nochmal: Weil du gar nicht weißt, dass das Objekt intern ein Vektor speichert.

    Betrachte doch ein Objekt einfach mal wie eine Blackbox. Du weißt was du hineingeben kannst und was du herausbekommen kannst, aber nicht was innen drin passiert.
    Öffentliche Attribute verletzen dieses Blackbox-Prinzip, da sie Klasseninterna preisgeben.

    Du meinst, bei trivialen Gettern/Settern kann man auch öffentliche Attribute verwenden. Ich denke, das sollte man nicht machen, weil man sich so die Flexibiltät raubt, später die Implementation zu ändern.

    Ein weiteres, jedoch weniger wichtiges Argument, ist, dass man so ein konsistentes Interface erhält, da ja nicht alle Attribute einer Klasse zwingenderweise direkt in der Klasse direkt gespeichert sind, sondern evtl. aus anderen Werten errechnet werden müssen. Trotzdem greift man auf die gleiche Art und Weise auf diese "Attribute" zu.
    Kleines Beispiel:

    class Triangle 
    {
    public:
      point a(); // a könnte auch ein public member vom Triangle sein
      void a(point new_a); // " 
    
      double area(); // Geht hier nicht mehr, da die Fläche nicht direkt im 
      vec normal();  // zwischengespeichert wird
    
    private:
      point m_a, m_b, m_c;
    };
    


  • otze, I am disappoint



  • Nick Unbekannt schrieb:

    Und wenn du jetzt schon festgestellt hast, dass dein Foo nicht die einzelnen Komponenten des Vectors kennen muss

    Das sagst du, nicht ich. Ich kann die Vektordarstellung schöner finden, weil es mir meine Arbeit erleichtert. Vielleicht bringt MyVector einfach ganz viele tolle Operationen, die ich einfach brauche. Trotzdem kann die Klasse immer noch genau so die einzelnen Werte verwenden. Und in der Tat kennt Foo immer noch alle Werte, nur nicht ihre Implementation.

    Konsequenterweise müsste dein getX bis getZ in den Vector wandern und du den Vector zurück geben.

    Nö, warum. Das ist ein Implementationsdetail.Ich kann dir mal ein konkreteres Beispiel nennen: Quaternionen. Intern macht es unglaublich Sinn, den komplexen Teil als 3D-Vektor darzustellen, einfach weil sich das Quat-produkt auf Skalar und Kreuzprodukt abbilden lässt. Trotzdem IST es kein Vektor und für viele Anwendungen macht die Interpretation als Vektor auch gar keinen Sinn. Warum also nach außen öffentlich machen, dass man intern die Werte als Vektor speichert?



  • LesenBildet schrieb:

    Nochmal: Weil du gar nicht weißt, dass das Objekt intern ein Vektor speichert.

    Doch in dem Fall schon, deswegen ist auch das Beispiel unpassend. Entweder Foo ist ein Vektor und hat deswegen auch getX bis getZ. Oder Foo hat einen Vektor, dann kann man den Vektor aber auch Vektor sein lassen.

    LesenBildet schrieb:

    Du meinst, bei trivialen Gettern/Settern kann man auch öffentliche Attribute verwenden. Ich denke, das sollte man nicht machen, weil man sich so die Flexibiltät raubt, später die Implementation zu ändern.

    Die Ausgangsfrage war eigentlich, ob man die geschützte Klasseninterna über eine Referenz der Öffentlichkeit preis geben soll? Dass dies bei reinen Containern Sinn macht ist verständlich. Aber wie weit ist die Sache noch davon entfernt einfach die Attribute public zu machen? Und da war und ist meine Ansicht, dass es keinen Unterschied gibt. Das selbe steht auch im verlinkten Artikel von brotbernd. Das heißt jetzt nicht, dass ich meine Attribute public mache. Nur gebe ich auch keine Attribute per non-const-Referenz aus der Klasse.


Anmelden zum Antworten