2009-08-06 4 views
3

Gibt es in C++ einen Grund, nicht über eine Klasseninstanz auf statische Membervariablen zuzugreifen? Ich weiß, dass Java die Stirn runzelt und sich fragt, ob es in C++ eine Rolle spielt. Beispiel:C++: Zugang const Mitglied vars durch die Klasse oder eine Instanz?

class Foo { 
    static const int ZERO = 0; 
    static const int ONE = 1; 
    ... 
}; 


void bar(const Foo& inst) { 
    // is this ok? 
    int val1 = inst.ZERO; 
    // or should I prefer: 
    int val2 = Foo::ZERO 
    ... 
}; 

Ich habe eine zweite Bonusfrage. Wenn ich ein statisches Double deklariere, muss ich es irgendwo definieren und diese Definition muss den Typ wiederholen. Warum muss der Typ wiederholt werden? Zum Beispiel:

In a header: 
    class Foo { 
    static const double d; 
    }; 
In a source file: 
    const double Foo::d = 42; 

Warum muss ich das "const double" Teil in meinem CPP-Datei wiederholen?

+2

Nicht ein genaues Duplikat, aber ich denke, dass die gleichen Antworten wahrscheinlich gelten: http://StackOverflow.com/Questions/840522/Given-Apointer-to-Ac-Object-what-is-the-prefered-way -to-call-a-static-membe –

+0

Ja. Lesen Sie die Antwort von Adam Rosenthal aus einem sehr guten Grund, warum Sie die Klasse als Präfix anstelle einer Instanz bevorzugen sollten. – quark

Antwort

5

Für die erste Frage, abgesehen von der Frage des Stils (es macht es offensichtlich, dass es eine Klassenvariable ist und kein zugeordnetes Objekt), Fred Larsen, in Kommentaren auf die Frage, verweist auf vorherige Frage. Lesen Sie Adam Rosenthal's answer für sehr guten Grund, warum Sie vorsichtig damit sein wollen. (. Ich würde up-Abstimmung Fred, wenn er es als Antwort geschrieben hatte, aber ich kann nicht so Kredit, wo es auf Grund Ich habe bis-Abstimmung Adam.)

Was Ihre zweite Frage:

Warum muss ich den "const double" -Teil in meiner cpp-Datei wiederholen?

Sie müssen den Typ hauptsächlich als Implementierungsdetail wiederholen: So interpretiert der C++ - Compiler eine Deklaration. Dies ist auch nicht unbedingt ideal für lokale Variablen, und C++ 1x (früher C++ 0x) verwendet das Schlüsselwort auto, um zu vermeiden, dass es für reguläre Funktionsvariablen wiederholt werden muss.

So folgt aus:

vector<string> v; 
vector<string>::iterator it = v.begin(); 

kann dies werden:

vector<string> v; 
auto it = v.begin(); 

Es gibt keinen ersichtlichen Grund, warum dies nicht mit statischen als auch, so in Ihrem Fall könnte thos:

const double Foo::d = 42; 

könnte dies gut werden.

static Foo::d = 42; 

Der Schlüssel ist einige Weg des Identifizierens dies als eine Erklärung zu haben.

Hinweis sagen, dass ich keine klar Grund: C++ 's Grammatik ist eine lebende Legende: es ist extrem hart alle seine Grenzfälle abzudecken. Ich denke nicht das oben genannte ist mehrdeutig, aber es könnte sein. Wenn nicht, könnten sie das zur Sprache hinzufügen. Erzähl ihnen davon ... für C++ 2x: /.

6

Ich würde Foo::ZERO über inst.ZERO bevorzugen, weil es deutlicher sagt, was vor sich geht. Bei einer Methode der Klasse Foo würde ich jedoch einfach ZERO verwenden.

Wie bei der Bonusfrage ist const nur Teil des vollständigen Typs.

+0

Ich verstehe, dass const Teil des Typs ist. Ich frage mich, warum ich den Typ überhaupt wiederholen muss. Ich möchte nur sagen: Foo :: d = 42; Es gibt nur einen Foo :: d in der Header-Datei deklariert. Stellt dies die Möglichkeit einer Zweideutigkeit dar, die ich hier nicht sehe? Könnte es eine Mitgliedsfunktion namens d geben? Ich weiß, dass es einen guten Grund gibt, den Typ zu wiederholen, ich weiß einfach nicht, was das ist. – criddell

+0

Vielleicht sind das nur die Regeln für die Sprache? – Juan

+0

Ich versuchte, dies in einem Kommentar zu erklären, aber lief aus dem Zimmer (Seufzer). Ich beantworte es unten. – quark

3

Vorausgesetzt, dass Sie sie als statisch deklarieren und sie zu Klassenkonstanten machen, würde ich Foo :: Zero verwenden, um die Absicht dem gelegentlichen und nicht so flüchtigen Leser Ihres Codes mitzuteilen.

Ich würde auch die Namen aller Großbuchstaben der Konstanten ersetzen, dh Foo :: ZERO in Foo :: Zero verwandeln. Die übliche Konvention für Präprozessor-Makros besteht darin, sie in Großbuchstaben zu benennen und ein ähnliches Benennungsschema für Ihre C++ - Konstanten zu verwenden, da Probleme auftreten, weil der Präprozessor möglicherweise über Ihre C++ - Konstanten blättert und Sie sehr interessante Fehlermeldungen erhalten.

+0

Wow - guter Punkt auf der Namenskonvention. Ich bin tatsächlich mehr als einmal davon gebissen worden (bitte, jeder - hör auf # PI zu definieren!) – criddell

1

Ich würde Foo :: ZERO verwenden, aber das ist nur ich. Vor allem, wenn Sie von Foo abstammen, was verwirrend wird.

Für Ihre zweite Frage müssen Sie Speicher für den doppelten Wert erstellen, und das geschieht in einer Implementierungseinheit.

Ich denke, der einzige Typ, den Sie Speicher für nicht erstellen müssen, ist ein const Integraltyp. Sie können den Wert dann in die Header-Datei einfügen. Da es jedoch keine Adresse hat, können Sie sie nicht durch Verweis auf eine Funktion übergeben, es sei denn, Sie fügen eine Definition in eine CPP-Datei ein. (Dies scheint die Art zu sein, wie es mit gcc funktioniert).

1

Es spielt keine Rolle, welche Form Sie in Ihrem Beispiel verwenden. Beide meinen dasselbe. Ich würde es vorziehen, den Klassenweg im Allgemeinen zu verwenden, weil Sie nicht immer eine Instanz zur Verfügung haben, um den Punktoperator zu verwenden.

Es ist schön, beide Optionen zu haben, wenn Sie jemanden in Betracht ziehen, der eine Template-Funktion schreibt. Sie haben die Funktion möglicherweise mit dem Punktoperator codiert. Ihre Klasse mit dem statischen Klassenmitglied kann weiterhin zum Instanziieren der Vorlage verwendet werden, da diese Syntax unterstützt wird.

Was Ihre Bonusfrage angeht, so ist die Sprache genau so. Sie müssen immer den vollen Typ deklarieren. Sie sollten das wahrscheinlich in einer separaten Frage fragen.

1

persönlich würde ich eine anonyme Enum verwenden. Endergebnis ist genau das gleiche obwohl :)

Wie für Ihre Fragen. Ich würde definitiv das Foo :: Zero bevorzugen, weil es offensichtlich ist, wenn man darauf schaut, worauf man zugreift. inst.Zero erfordert, dass Sie herausfinden, welcher Typ inst ist.

Sie müssen den Datentyp wiederholen, weil so C++ funktioniert.Auf die gleiche Weise, wenn Sie Folgendes in eine Header-Datei geschrieben haben.

extern int foo; 

Sie werden immer noch die

int foo 

in einer CPP-Datei erwähnen müssen. Wie bereits erwähnt, deklarieren Sie eine Variable vom Typ "const int". Daher muss "const int" in der Definition der Variablen wiederholt werden.

+0

anonyme enums erzwingen eine bestimmte Speichergröße (int). Wenn Sie möchten, dass die Konstanten einen anderen Typ haben, können Sie keine anonymen Enums verwenden. –