Access Modifier in jede Zeile



  • Hallo zusammen,

    ich hab eine ziemlich große und unübersichtliche Header-Datei, bei der man manchmal garnicht mehr weiß, ob eine Funktion "public" oder "private" etc. ist. Ich frage mich gerade, warum man in C++ die Modifizierer nicht vor jede Deklaration schreibt:

    protected: void foo();
    private: bool bar( int param ) { return true; }
    protected: std::string snafu();
    public: int i;
    

    Spricht da was dagegen, außer dass zum Beispiel Visual Studio das immer umformatieren will?

    Vielen Dank im Voraus.



  • Weil es einfach bequemer ist. Wieso ist es nicht möglich, Deine Datei so zu organisieren, dass zuerst der public-Teil kommt, dann der protected-Teil, dann der private-Teil?
    So:

    ...
    {
      public:
        ...
        ...
        ...
    
      protected:
        ...
        ...
    
      private:
        ...
    }
    

    Eventuell noch mit Kommentaren abgesetzt bzw. kenntlich gemacht, dann kann das doch gar nicht unübersichtlich werden ...?!



  • arijeh schrieb:

    Spricht da was dagegen, außer dass zum Beispiel Visual Studio das immer umformatieren will?

    Ja. Es ist völlig unübersichtlich.

    Wenn deine Header-Datei so groß ist, dass du bei einer vernünftigen Formatierung nicht mehr durchblickst, solltest du dringend über das Klassendesign nachdenken.

    Du solltest folgendes beachten:

    * nur jeweils ein Block für public, private, protected.
    * Wenn es immer noch zu unübersichtlich wird, kannst du die Methoden gruppieren. Du musst dabei nicht auf doxygen-Tags zurückgreifen wie in dem Beispiel unten. Eine einfache Kommentarzeile reicht auch, wenn du keine doxygen-Doku erstellen willst.

    class MyClass
    {
      public:
    
        // @name Attribute Access
        // @{
        bool IsActivated() const;
        double GetDoubleValue() const;
        void SetDoubleValue(double value);
        // @}
    
        // @name Processing
        // @{
        void DoSomething();
        double CalculateComplexStuff(double input);
        // @}
    };
    


  • Danke für die schnellen Antworten. Also mit dem Überdenken des Klassendesigns stimme selbstverständlich zu. Allerdings hab ich hier ca. 1.000.000 Zeilen an legacy code am Hals und die fragliche Header-Datei alleine hat über 25.000 Zeilen. Ich hab das nicht verbrochen, aber was mich in dieser Situation ein bisschen stört ist, dass C++ einen "zwingt", die Deklarationen nach Typ zu gruppieren anstelle sie sachlich zusammenzufassen. Es ist doch viel sinnvoller, dass zusammengehöige Funktionen zusammenstehen, als dass man sie nach ihrer Zugriffsart sortiert. In Java/C# etc ist es ja auch so...

    Aber ohne eine Grundsatzdiskussion auslösen zu wollen ist die eigentliche Frage die, ob, wenn ich es so mache, es vielleicht performance- oder compilertechnisch iregndwelche Nachteile hat?



  • arijeh schrieb:

    aber was mich in dieser Situation ein bisschen stört ist, dass C++ einen "zwingt", die Deklarationen nach Typ zu gruppieren anstelle sie sachlich zusammenzufassen.

    Das tut es ja nicht, Du kannst das selbstverständlich abwechselnd machen oder sonstwie mischen.
    Aber dadurch wird es doch nicht übersichtlicher, sondern eher das Gegenteil.
    Ein Benutzer der Klasse interessiert sich doch für seine Schnittstelle, also das was public deklariert ist, der Rest ist ihm völlig wumpe.

    Und sich das dann rauszusuchen, wenn da in jeder zweiten Zeile sich public, private, protected abwechseln, das ist sehr frustrierend.



  • Nein C++ zwingt einen nicht.

    Solange du die Deklarationen von den Definitionen trennst hast du fast alle Freiheiten.

    Ok, so Späße wie typedefs müssen vor der Benutzung stehen (logischerweise) und auch da muss die Reihenfolge stimmen. Aber ansonsten musst du eigentlich nichts beachten.

    Ich mach das immer etwa so:

    class Foo
    {
    [public] // je nachdem ob es öffentlich sein soll oder nicht
        typedef alle hier;
    
    public:
        Constructors();
        // alle auch Copy und Copy-Assignment Constructor
        ~Destructor();
        void swap(Foo &); // Hilfsfunktionen wie swap
    
    public:
        // Accessfunktionen wie Getter/Setter
        // oder operator[]
        // Späße wie size und sowas alles
    
    public:
        // jetzt die eigentlichen "Arbeitsfunktionen", z.B.
        void traverse();
    
    public:
        // weitere Arbeitsfunktionen, nach Aufgaben gestaffelt
    
    private:
        // Membervariablen
        int x;
    
    private:
        // die "helfenden" Privaten Methoden, auch gestaffelt nach Zuständigkeit und Aufgaben
    };
    


  • Kleine Zwischenfrage:

    class Bla{
    public:
    ...
    private:
    ...
    }
    

    ist dasselbe wie

    struct Bla{
    ...
    private:
    ...
    }
    

    Wieso fängt jeder mit class public: an wenn struct genau das tut? Wird das als Coding-Convention benutzt, alla struct = POD, class = Nicht-POD?



  • nwp3 schrieb:

    Wieso fängt jeder mit class public: an wenn struct genau das tut? Wird das als Coding-Convention benutzt, alla struct = POD, class = Nicht-POD?

    Technisch gesehen ist das das Gleiche. Rein technisch. Von der Semantik her machen Leute eine relativ starke Unterscheidung zwischen den beiden. struct ist eher ein statisches Konstrukt (schon fast wie ein Container) und class ist eine lebendiges, dynamisches Element des Programms wo auch viel mehr passiert.

    Edit: Und nein, nicht jeder fängt mit public an.



  • Das machen viele unterschiedlich.

    Manche schreiben die Membervariablen oben hin, damit man diese sofort sieht.
    Andere wollen sie "verstecken" (nämlich ganz unten).

    Ich selbst nutze Klassen (also class) wenn ich wirkliche Klassen schreibe, mit Methoden und Funktionalität.

    Struct nutze ich, wenn ich eine Sammlung von Daten hab, die maximal ein paar Konstruktoren haben um die Objekte ordentlich zu initialisieren.



  • Du hast mit legacy code zu tun und deshalb Probleme mit der 25kloc-Header-Klasse. Es ist natürlich löblich, dass du da Hand anlegst, um die Klasse etwas übersichtlicher zu gestalten. Allerdings sollte es sich dabei nicht um reine Kosmetik handeln, das kannst du dir auch sparen. Wenns nur als allererster Schritt gedacht ist, wäre es vielleicht noch sinnvoll, alle N Zeilen einen Access Modifier einzubauen, damit man nicht durch die halbe Welt scrollen muss, aber jede Zeile ist übertrieben.

    Wenn du aber eh schon die Finger in der Klasse hast, solltest du wenigstens auch anfangen, sie aufzubrechen, sprich erst eine gute Abdeckung mit Unittests erreichen (falls noch nicht vorhanden) und dann Stück für Stück Zeugs rausziehen.


Anmelden zum Antworten