2010-04-11 9 views
6

A „traditionellen“ C++ Klasse (nur einige zufällige Erklärungen) könnte folgendermaßen aussehen:C++ Klasse Zugriffsbezeichner Ausführlichkeit

class Foo 
{ 
public: 
    Foo(); 
    explicit Foo(const std::string&); 
    ~Foo(); 

    enum FooState 
    { 
    Idle, Busy, Unknown 
    }; 

    FooState GetState() const; 
    bool GetBar() const; 
    void SetBaz(int); 

private: 
    struct FooPartialImpl; 

    void HelperFunction1(); 
    void HelperFunction2(); 
    void HelperFunction3(); 

    FooPartialImpl* m_impl; // smart ptr 
    FooState m_state; 
    bool m_bar; 
    int m_baz; 
}; 

Ich fand immer diese Art der Zugriffsebene Spezifikation hässlich und schwer zu folgen, wenn der ursprüngliche Programmierer hat seine "Zugangsbereiche" nicht ordentlich organisiert.


einen Blick auf die Schnipsel in einem Java/C# Stil machen, erhalten wir:

class Foo 
{ 
    public: Foo(); 
    public: explicit Foo(const std::string&); 
    public: ~Foo(); 

    public: enum FooState 
    { 
    Idle, Busy, Unknown 
    }; 

    public: FooState GetState() const; 
    public: bool GetBar() const; 
    public: void SetBaz(int); 

    private: struct FooPartialImpl; 

    private: void HelperFunction1(); 
    private: void HelperFunction2(); 
    private: void HelperFunction3(); 

    private: FooPartialImpl* m_impl; // smart ptr 
    private: FooState m_state; 
    private: bool m_bar; 
    private: int m_baz; 
}; 

Meiner Meinung nach ist dies viel einfacher in einem Header zu lesen, weil die Zugriffsbezeichner richtig neben dem Ziel, und nicht ein paar Zeilen entfernt. Ich fand dies besonders zutreffend, wenn ich mit Header-only Template-Code arbeitete, der nicht in das übliche "* .hpp/* .inl" -Paar getrennt war. In diesem Szenario überwältigte die Größe der Funktionsimplementierungen diese kleine, aber wichtige Information.

Meine Frage ist einfach und rührt von der Tatsache her, dass ich noch nie jemanden gesehen habe, der dies aktiv in ihrem C++ Code macht.

Angenommen, ich habe keine "Class View" -fähige IDE, gibt es irgendwelche offensichtlichen Nachteile bei der Verwendung dieser Ausführlichkeitsstufe?

Alle anderen Stil Empfehlungen sind willkommen!

+0

Wie für Vorlagenfunktionsdefinitionen direkt in der Klassendefinition ... das ist okay für Einzeiler, aber es macht es wirklich schwer, die Klassenschnittstelle zu verstehen, sobald sie wächst. Ich persönlich teile meinen Header nicht in .h/.i, sondern setze die Definitionen der * big * -Funktionen am Ende der Datei. –

Antwort

10

"Wenn in Rom, tun Sie wie die Römer tun."

Ich, ich habe viel Zeit mit Java verbracht, wie die Art, Zugriffsspezifizierer für jedes Feld und jede Methode separat zu spezifizieren. Wenn ich jedoch in C++ programmiere, verwende ich immer den Stil, der in Ihrem ersten Code-Snippet gezeigt wird.

+0

Gut zu sehen, haben Sie Ihren Namen behoben: D –

+0

Ja, es ist eine gute Sache. – GManNickG

+0

Gibt es einen Prozess? Ich ging und nannte mich nach ein paar Körner ... – Potatoswatter

5

Persönlich finde ich es sehr ärgerlich, den Zugriffsqualifikator für jedes Symbol angeben zu müssen. Es macht Dinge schwieriger zu lesen, nicht einfacher, und fördert die sehr schlechte Angewohnheit, private und öffentliche Dinge innerhalb der Klassendefinition frei zu mischen. Ich sehe diese Art von Chaos die ganze Zeit. In C# versuche ich dies mit #region private usw. zu mildern, was hoffentlich zukünftigen Betreuern hilft, die Dinge sauber zu halten.

+0

Ha! Ich gewinne um 4 Sekunden. +1 :) –

+1

Re: Regionen; Wenn ich in VS arbeite und Windows-spezifischen Code schreibe, versuche ich auch die # pragma region/endregion-Direktiven zu verwenden. Es ist ziemlich nett, dass VS dies für C++ unterstützt. – PolyTex

1

Es ist nichts falsch daran, obwohl Sie Augenbrauen heben werden. Der Hauptvorteil, die Zugriffsspezifizierer getrennt zu halten, besteht darin, alle privaten Mitglieder und Methoden an die Spitze der Klasse zu setzen - zusammen.

Wenn Ihre Klasse zu groß ist, um auf einen Bildschirm zu passen, sollte sie wahrscheinlich in mehr als eine Klasse aufgeteilt sein, und/oder alle impliziten Inline-Funktionen sollten explizit inline deklariert werden, wenn die Implementierung aus der Klasse entfernt wird.

+0

Ich weiß nicht, was es ist, aber die erste Version sieht einfach "aus" zu mir. Vielleicht weil ich in den letzten Wochen hauptsächlich in C# gearbeitet habe? – PolyTex

+0

@PolyTex: Vielleicht, aber in diesem Fall verzichte ich auf Rahul G - ich hasse Unicorns 'Antwort. (Ich kann nicht glauben, dass ich das gerade ernsthaft eingegeben habe ...) –

+0

Sie brauchen nicht enthalten * Ich hasse Unicorns * in meinem Namen. Ich habe meinen Namen am 1. April geändert und jetzt bleibe ich für einen Monat dran. :( – missingfaktor

0

Der Nachteil des letzteren Ansatzes ist, dass dies selten getan wird, und es ist keine gute Idee, andere Entwickler auf diese Weise zu überraschen, und es erfordert, dass der Zugriffsmodifizierer millionenfach getippt wird. Die Verwendung des traditionellen Ansatzes wird es ersparen, unnötigerweise den Modifizierer immer wieder eingeben zu müssen und ist auch der erwartete Ansatz.

0

In der Tat macht es semantisch keinen Unterschied, aber Sie werden sich selbst und Ihren Kollegen einen großen Gefallen tun, wenn Sie nur dem folgen, was akzeptiert wird.

Persönlich mag ich meine Klasse wie folgt:

struct S { 
    S(int m) : m(m) { } 
    S(const S& o); 
    S& operator=(const S& o); 

    void f() const; 
    std::string g(); 

private: 
    void help(); 

private: 
    int m; 
}; 

Aber ich werde meine Manieren ändern, ohne zu überlegen, ob ich in ein Repository zu begehen, die nicht streng ist mein, weil ich weiß, wie dankbar ich sein würde wenn jemand meinen Code in meine Repositories einträgt, indem er meinen Gewohnheiten folgt.

Verwandte Themen