636 Stimmen

Wie initialisiert man private statische Mitglieder in C++?

Wie lässt sich ein privates, statisches Datenelement in C++ am besten initialisieren? Ich habe dies in meiner Header-Datei versucht, aber es gibt mir seltsame Linker-Fehler:

class foo
{
    private:
        static int i;
};

int foo::i = 0;

Ich vermute, dies ist, weil ich ein privates Mitglied von außerhalb der Klasse nicht initialisieren kann. Was ist also der beste Weg, dies zu tun?

671voto

Martin York Punkte 245363

Die Klassendeklaration sollte in der Header-Datei stehen (oder in der Quelldatei, wenn sie nicht gemeinsam genutzt wird).
Datei: foo.h

class foo
{
    private:
        static int i;
};

Aber die Initialisierung sollte in der Quelldatei erfolgen.
Datei: foo.cpp

int foo::i = 0;

Befindet sich die Initialisierung in der Header-Datei, dann hat jede Datei, die die Header-Datei enthält, eine Definition des statischen Mitglieds. Während der Link-Phase kommt es daher zu Linker-Fehlern, da der Code zur Initialisierung der Variablen in mehreren Quelldateien definiert wird. Die Initialisierung der static int i muss außerhalb einer Funktion durchgeführt werden.

Nota: Matt Curtis: weist darauf hin, dass C++ eine Vereinfachung der obigen Ausführungen erlaubt, wenn die statische Mitgliedsvariable vom Typ const int ist (z. B. int , bool , char ). Sie können dann die Mitgliedsvariable direkt innerhalb der Klassendeklaration in der Header-Datei deklarieren und initialisieren:

class foo
{
    private:
        static int const i = 42;
};

115voto

Matt Curtis Punkte 22328

Für eine variabel :

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

Das liegt daran, dass es nur eine Instanz von foo::i in Ihrem Programm. Es ist sozusagen das Äquivalent zu extern int i in einer Header-Datei und int i in einer Quelldatei.

Für eine Konstante können Sie den Wert direkt in die Klassendeklaration aufnehmen:

class foo
{
private:
    static int i;
    const static int a = 42;
};

112voto

Die in Sente Punkte 9197

Seit C++17 können statische Mitglieder im Header mit der Option Inline Stichwort.

http://en.cppreference.com/w/cpp/language/static

"Ein statisches Datenelement kann inline deklariert werden. Ein statisches Inline-Datenelement kann in der Klassendefinition definiert werden und kann einen Standardinitialisierer für das Element angeben. Es benötigt keine Definition außerhalb der Klasse:"

struct X
{
    inline static int n = 1;
};

35voto

Joshua Clayton Punkte 1597

Für künftige Betrachter dieser Frage möchte ich darauf hinweisen, dass Sie vermeiden sollten, was monkey0506 schlägt vor .

Header-Dateien sind für Deklarationen.

Header-Dateien werden einmal für jede .cpp Datei, die direkt oder indirekt #includes und Code außerhalb einer Funktion wird bei der Programminitialisierung ausgeführt, bevor main() .

Durch das Setzen: foo::i = VALUE; in die Kopfzeile, foo:i wird der Wert VALUE (was auch immer das ist) für jeden .cpp Datei, und diese Zuweisungen erfolgen in unbestimmter Reihenfolge (vom Linker bestimmt) vor main() ausgeführt wird.

Was wäre, wenn wir #define VALUE eine andere Nummer in einem unserer .cpp Dateien? Es wird sich gut kompilieren lassen, und wir werden nicht wissen können, welche Datei gewinnt, bis wir das Programm ausführen.

Fügen Sie niemals ausgeführten Code in eine Kopfzeile ein, aus dem gleichen Grund, aus dem Sie niemals #include a .cpp Datei.

Include Guards (die Sie meiner Meinung nach immer verwenden sollten) schützen Sie vor etwas anderem: der gleichen Kopfzeile, die indirekt #include d bei der Kompilierung einer einzelnen .cpp Datei.

23voto

Johann Gerell Punkte 24065

Mit einem Microsoft-Compiler[1] werden statische Variablen, die nicht int -like kann auch in einer Header-Datei definiert werden, aber außerhalb der Klassendeklaration, unter Verwendung der Microsoft-spezifischen __declspec(selectany) .

class A
{
    static B b;
}

__declspec(selectany) A::b;

Ich sage nicht, dass dies gut ist, ich sage nur, dass es möglich ist.

[1] Heutzutage unterstützen mehr Compiler als MSC __declspec(selectany) - zumindest gcc und clang. Vielleicht sogar mehr.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X