Wie initialisiere ich ein statisches const-Mitglied in C ++?

73

Ist es möglich, einen statischen const-Wert außerhalb des Konstruktors zu initialisieren? Kann es an derselben Stelle initialisiert werden, an der Mitgliedererklärungen gefunden werden?

class A {
private:
  static const int a = 4;
  /*...*/
};
Anarhikos
quelle
9
Ja, was Sie haben, funktioniert (aber nur für integrale Typen).
Onkel Bens
3
Ich wollte nur hinzufügen, dass dies staticnichts mit Konstruktoren zu tun hat, da staticMitglieder nicht spezifisch für eine bestimmte Instanz sind und außerhalb dieser existieren.
Am
Tatsächlich müssen Sie die Konst-Statik außerhalb eines Klassenkonstruktors initialisieren. Sonst wäre es keine konstante Statik. DUCY?
John Dibling
Mögliches Duplikat von C ++, wo statische
Konstante

Antworten:

84

JA können Sie aber nur für int-Typen. Wenn Sie möchten, dass Ihr statisches Mitglied ein anderer Typ ist, müssen Sie es irgendwo in einer CPP-Datei definieren.

class A{
private:
 static const int a = 4; // valid
 static const std::string t ; // can't be initialized here
 ...
 ...
};


// in a cpp file where the static variable will exist 
const std::string A::t = "this way it works";

Beachten Sie außerdem, dass diese Regel in C ++ 11 entfernt wurde. Jetzt können Sie (mit einem Compiler, der die Funktion bereitstellt) das, was Sie möchten, direkt in der Klassenmitgliedsdeklaration initialisieren.

Klaim
quelle
2
@anarhikos - Die In-Class-Initialisierung funktioniert nur für integrale Typen. doubleist kein integraler Typ.
Brian Neal
1
@anrhikos: Deshalb solltest du nicht innerhalb der Klasse definieren. Sie sollten außerhalb der Klasse als eine Frage der Praxis definieren (siehe meine Antwort)
Was ist, wenn ich keinen Wert zuweisen möchte? Was ist, wenn nur der Standardkonstruktor ausgeführt werden soll? Ich erhalte Fehler beim erneuten Deklarieren der Variablen außerhalb der Klasse, wenn ich nichts zuweise.
Ben Farmer
1
@anarhikos, müssen Sie inline vor statischen const (C ++ 17) oder constexpr
Zhang
34

Statische Datenelemente (nur C ++)

Die Deklaration eines statischen Datenelements in der Mitgliederliste einer Klasse ist keine Definition. Sie müssen das statische Element außerhalb der Klassendeklaration im Namespace-Bereich definieren. Zum Beispiel:

class X
{
public:
      static int i;
};
int X::i = 0; // definition outside class declaration

Sobald Sie ein statisches Datenelement definiert haben, ist es vorhanden, obwohl keine Objekte der Klasse des statischen Datenelements vorhanden sind. Im obigen Beispiel sind keine Objekte der Klasse X vorhanden, obwohl das statische Datenelement X :: i definiert wurde.

Statische Datenelemente einer Klasse im Namespace-Bereich sind extern verknüpft. Der Initialisierer für ein statisches Datenelement befindet sich im Bereich der Klasse, die das Element deklariert.

Ein statisches Datenelement kann von einem beliebigen Typ sein, mit Ausnahme von void oder void, die mit const oder volatile qualifiziert sind. Sie können ein statisches Datenelement nicht als veränderbar deklarieren.

Sie können nur eine Definition eines statischen Elements in einem Programm haben. Unbenannte Klassen, Klassen in unbenannten Klassen und lokale Klassen dürfen keine statischen Datenelemente haben.

Statische Datenelemente und ihre Initialisierer können auf andere statische private und geschützte Mitglieder ihrer Klasse zugreifen. Das folgende Beispiel zeigt, wie Sie statische Elemente mit anderen statischen Elementen initialisieren können, obwohl diese Elemente privat sind:

class C {
      static int i;
      static int j;
      static int k;
      static int l;
      static int m;
      static int n;
      static int p;
      static int q;
      static int r;
      static int s;
      static int f() { return 0; }
      int a;
public:
      C() { a = 0; }
      };

C c;
int C::i = C::f();    // initialize with static member function
int C::j = C::i;      // initialize with another static data member
int C::k = c.f();     // initialize with member function from an object
int C::l = c.j;       // initialize with data member from an object
int C::s = c.a;       // initialize with nonstatic data member
int C::r = 1;         // initialize with a constant value

class Y : private C {} y;

int C::m = Y::f();
int C::n = Y::r;
int C::p = y.r;       // error
int C::q = y.f();     // error

Die Initialisierungen von C :: p und C :: q verursachen Fehler, da y ein Objekt einer Klasse ist, die privat von C abgeleitet ist und deren Mitglieder Mitgliedern von C nicht zugänglich sind.

Wenn ein statisches Datenelement vom Typ const-Integral oder const-Aufzählung ist, können Sie in der Deklaration des statischen Datenelements einen konstanten Initialisierer angeben. Dieser konstante Initialisierer muss ein integraler konstanter Ausdruck sein. Beachten Sie, dass der Konstanteninitialisierer keine Definition ist. Sie müssen das statische Element weiterhin in einem umschließenden Namespace definieren. Das folgende Beispiel zeigt dies:

#include <iostream>
using namespace std;

struct X {
  static const int a = 76;
};

const int X::a;

int main() {
  cout << X::a << endl;
}

Die Token = 76 am Ende der Deklaration des statischen Datenelements a sind ein konstanter Initialisierer.


quelle
16

Der Vollständigkeit halber füge ich die statischen Vorlagenelementvariablen hinzu.

template<class T> struct X{
   static T x;
};

template<class T> T X<T>::x = T();

int main(){
   X<int> x;
}
Chubsdad
quelle
Danke @Chubsdad fürs Teilen! Es war sehr schwer, die richtige Syntax zu finden.
Benutzer
7

Sie können statische Elemente in Konstruktoren nicht initialisieren. Integrale Typen können Sie bei ihrer Deklaration inline initialisieren. Andere statische Elemente müssen (in einer .cpp) Datei definiert sein:

// .h
class A{
private:
 static const int a = 4;
 static const foo bar;
 ...
 ...
};

// .cpp
const foo A::bar = ...;
sbi
quelle