Compiler findet Ctor nicht



  • SchlechterCodeGefunden schrieb:

    Schreib anstatt panName einmal panName.c_str() .
    Kann es zufälligerweise sein, dass du von Java kommst und keine Ahnung von normalem C++ hast?

    Was ist denn bitte an dem Code so unglaublich schlecht Mr. Perfekt?

    Mir konnte noch immer keiner beantworten, wo die ganzen Referenzen in der Signatur herkommen.



  • CtorGesucht schrieb:

    Mir konnte noch immer keiner beantworten, wo die ganzen Referenzen in der Signatur herkommen.

    Weil das der Default ist. Woher soll der Compiler bei einer Funktion wissen, ob sie eine Referenz annimmt oder nichtm bevor er sie gefunden hat? Bei dir sieht er nur: "Aha, die Argumente können alle referenziert werden" und macht erstmal Referenzen draus. Danach sucht er nach Funktionen, die eine dazu kompatible Signatur haben. Ganz einfach. Umgekehrt geht das übrigens nicht. Du kannst zum Beispiel keine Referenz nachträglich an eine temporäre Variable binden.

    Und unglaublich schlecht sind deine abstrus vielen Parameter



  • CtorGesucht schrieb:

    Was ist denn bitte an dem Code so unglaublich schlecht Mr. Perfekt?

    1. Viel zu langer Konstruktor, unübersichtlicher geht's nicht mehr
    2. So was wird von Memberfunktionen abgenommen
    3. Warum Pointer (damit man sie bei den Defaultwerten auf null setzen kann ist keine Ausrede)
    4. Warum NULL (hier nimmt man 0)
    5. Komische Benennung
    6. erst minPan klein, dann MaxPan gross
    7. W3D gefällt mir nicht
    8. Verwendung von new (besonders gravierend)
    9. ohne Anspruch auf Vollständigkeit

    Aber eigentlich kann es mir egal sein, mein Code ist immer perfekt.

    Die Frage mit den Referenzen hab ich überlesen, aber jetzt gerade ist sie zufriedenstellend beantwortet worden.



  • 1. Wie würdest du es lösen, wenn du die Parameter in deinem Objekt benötigst?
    2. Bitte? Wenn die Parameter zum erstellen des Objektes notwendig sind, wo gehören sie dann hin?
    3. Ist doch eine Ausrede, oder wie sieht deine Lösung aus?
    4. Auch hier wieder, welchen Sinn soll das haben? Bei NULL sehe ich sofort, dass ist ein ungültiger Zeiger. Bei 0 muss ich erst zweimal hinsehen, ob ich hier nicht einfach nur eine Zahl zuweise.
    6. Was soll an new gravierend sein?



  • SchlechterCodeGefunden schrieb:

    CtorGesucht schrieb:

    Was ist denn bitte an dem Code so unglaublich schlecht Mr. Perfekt?

    1. Viel zu langer Konstruktor, unübersichtlicher geht's nicht mehr
    2. So was wird von Memberfunktionen abgenommen
    3. Warum Pointer (damit man sie bei den Defaultwerten auf null setzen kann ist keine Ausrede)
    4. Warum NULL (hier nimmt man 0)
    5. Komische Benennung
    6. erst minPan klein, dann MaxPan gross
    7. W3D gefällt mir nicht
    8. Verwendung von new (besonders gravierend)
    9. ohne Anspruch auf Vollständigkeit

    Aber eigentlich kann es mir egal sein, mein Code ist immer perfekt.

    Die Frage mit den Referenzen hab ich überlesen, aber jetzt gerade ist sie zufriedenstellend beantwortet worden.

    War mir so klar, dass da nix dahinter ist. Alle deine Punkte sind totaler Quatsch.
    1. Du hast offenbar den Sinn eines Ctors nicht verstanden. Ein Ctor überführt die Instanz in einen funktionsfähigen Zustand. Wenn man diese Parameter braucht, dann ist das eben so.
    2. Falsch. Siehe 1.
    3. Hast es dir ja selber beantwortet.
    4. Irrelevant. Bei NULL sieht man einfach schneller, dass es sich um einen Pointer handelt.
    5. Ja, die Benennung ist komisch. Aber nur deshalb, weil ich schnell alle Bezeichner umbenannt hab in irgend ein Random Zeugs. Im echten Code sind die Bezeichner natürlich aussagekräftiger (W3D wäre ein Schrottname)
    6. Wie bitte? LOL. Ah verstehe. new ist also generell schlecht. Alles klar. Dann vielleicht auch const oder int?

    Dass genau solche Leute immer ne riesen Klappe haben... 🙄



  • Eigentlich ist keiner der Parameter notwendig, um das Objekt zu erstellen, daher wäre ein parameterloser Konstruktor angemessen.

    Es ist erstaunlich, wie sich die Threads wiederholen; in http://www.c-plusplus.net/forum/278266 wars genau gleich: ich (Schüler93) gebe die Lösung mit der Bemerkung, dass der Code schlecht ist und weise auf die Alternativen von NULL hin. Dann kommt `Nick Unbekannt' mit Halbwissen, das alles als falsch enttarnt wurde.

    Zu new : Smart Pointer sind besser, weil das dazu passende delete ganz sicher ausgeführt wird.

    Als Lösung schlage ich einfach folgendes vor:

    W3D wdd; // wird initialisiert, er braucht gar keine Parameter und ist gebrachsfähig
    wdd.fade_time() = 2; // Member wird initialisiert
    

    CtorGesucht schrieb:

    1. Du hast offenbar den Sinn eines Ctors nicht verstanden. Ein Ctor überführt die Instanz in einen funktionsfähigen Zustand. Wenn man diese Parameter braucht, dann ist das eben so.

    Scheinbar braucht man sie nicht, sonst gäbe es keine Default Parameter.

    Die Antworten zu 2. und 3. aktzeptiere ich nicht.
    Über 4. kann man sich wirklich streiten, von mir aus lässt du es halt so...
    In 5. sind wir uns einig, bis auf die Frage, ob man immer eine konsequente Benennung verwenden sollte
    6. sind die erwähnten Smart Pointer. const ist super, nimm das immer wenn möglich, int besser nicht (bei panCount wäre ein size_t besser geeignet)

    Aber ich glaube es ist besser, wenn ich es dabei belasse.



  • SchlechterCodeGefunden schrieb:

    wdd.fade_time() = 2; // Member wird initialisiert[/cpp]

    Was soll das sein? Du empfiehlst nicht ernsthaft eine Referenz auf einen privaten Member nach außen zu geben?



  • SchlechterCodeGefunden schrieb:

    W3D wdd; // wird initialisiert, er braucht gar keine Parameter und ist gebrachsfähig
    wdd.fade_time() = 2; // Member wird initialisiert
    

    Diese 2 Zeilen Code sagen eigentlich alles zu deinen C++ Kenntnissen. 😃



  • Die vielen Parameter machen die Sache recht unübersichtlich, war mMn. auch der Grund warum du den Fehler nicht selber sofort gesehen hast.
    Programmtechnisch problematisch kann deine Parameterübergabe von "panels" sein. Ist das eine Referenz auf eine Funktions-lokale Variable? Überlebt dein W3D-Objekt den Scope, zeigt der Member (wenn du den Zeiger speicherst) womöglich auf eine nicht mehr korrekte Stelle im Speicher -> SegFault.

    Ich würde ein wenig Refactoring betreiben. Ich seh z.B. gleich mehrere "pan"s in den Parametern. Kann man das nicht in eine eigene Klasse packen? Dann muss W3D weniger machen. Genauso 3 mit "time" - soll ein Timer sein? Dann kümmert sich jede Klasse um ihre eigenen Aufgaben, und W3D führt es zu einem sinnvollen Ganzen zusammen.

    Und wenn alle Parameter einen Default-Wert haben, sollte man wirklich über einen Default-Konstruktor nachdenken (wurde ja schon gesagt) Ein so fein strukturiertes Initialisieren ist nur in den wenigsten Fällen möglich, und dass die Reihenfolge nach Relevanz in jedem Fall eingehalten werden kann ist ebenfalls unwahrscheinlich -> meistens wird wohl ein Objekt ohne Parameter initalisiert, um danach die Member zu setzen, die auch wirklich gebraucht werden.
    Du kannst dir in deinem Code ja einfach mal anschauen, welche Werte du deinem Konstruktor im Endeffekt übergibst 😛 (Aber wahrscheinlich ist das auch wieder nur für uns hier...)

    Und dass dein "W3D" für das Forum abgeändert ist nehm ich dir so nicht ab. Da kommt noch ein "WBB" vor, die Dateien heißen auch "W3D.h/cpp" - da hast du dir ja mehr Mühe gegeben, deine Namen zu verschleiern als die Fehlermeldung zu lesen 😃



  • Doch, ich empfehle das (bei manchen Membern, die kein Update benötigen und keinen anderen Einschränkungen unterliegen). Kann natürlich auch ein Proxy sein, der das Objekt dann mit Überprüfung setzt.



  • l'abra d'or schrieb:

    Und dass dein "W3D" für das Forum abgeändert ist nehm ich dir so nicht ab. Da kommt noch ein "WBB" vor, die Dateien heißen auch "W3D.h/cpp" - da hast du dir ja mehr Mühe gegeben, deine Namen zu verschleiern als die Fehlermeldung zu lesen 😃

    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.

    Und das Beispiel mit der Funktion, die eine non-const Ref zurückgibst ist riesengroßer Bullshit. Genauso Bullshit wie der Tipp, generell new zu meiden und SmartPointer zu benutzen.



  • SchlechterCodeGefunden schrieb:

    Doch, ich empfehle das (bei manchen Membern, die kein Update benötigen

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

    SchlechterCodeGefunden schrieb:

    Kann natürlich auch ein Proxy sein, der das Objekt dann mit Überprüfung setzt.

    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.



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


Anmelden zum Antworten