wake-up-neo.net

Statische Daten Member-Initialisierung

Warum muss die Initialisierung statischer Datenelemente außerhalb der Klasse sein?

class X
{
public:
      int normalValue = 5; //NSDMI
      static int i;
};

int X::i = 0;

Warum ist das statische Datenelement (hier "i") nur eine Deklaration, keine Definition?

18
CyberGuy

Es ist wichtig, denInitialisierer zu unterscheiden, der seinen Anfangswert und die Definition angibt. Dieser geänderte Code ist gültig, wobei sich der Initialisierer in der Klassendefinition befindet:

class X
{
public:
  int normalValue = 5;
  static const int i = 0;       // declaration, with initializer
};

const int X::i;                 // definition

was außerhalb der Klasse sein muss, ist eine Definition, nicht die Initialisierung.

Das liegt daran, dass eine Variable eine Adresse im Speicher haben muss (es sei denn, sie wird nur in begrenzten Situationen verwendet, z. B. in konstanten Ausdrücken zur Kompilierzeit.)

Eine nicht statische Elementvariable ist in dem Objekt vorhanden, dessen Mitglied sie ist. Daher hängt ihre Adresse von der Adresse des Objekts ab, in dem sie enthalten ist. Jedes Mal, wenn Sie eine neue Xerstellen, erstellen Sie auch eine neue X::normalValue-Variable. Die Lebensdauer des nicht statischen Datenelements beginnt mit dem Konstruktor der Klasse. Die NSDMI-Syntax hat nichts mit der Adresse der Variablen im Speicher zu tun. Sie können lediglich einen Anfangswert an einer Stelle angeben, anstatt ihn in jedem Konstruktor mit einer expliziten Konstruktor-Initialisierungsliste zu wiederholen.

Andererseits ist eine statische Membervariable nicht in einer Instanz der Klasse enthalten, sie existiert unabhängig von einer einzelnen Instanz und existiert ab Programmstart an einer festen Adresse. Damit eine statische Member-Variable (oder ein anderes globales Objekt) eine eindeutige Adresse erhält, muss der Linker genau eine Definition der statischen Variablen in genau einer Objektdatei sehen und dieser eine Adresse zuweisen.

Da eine statische Variable genau eine Definition in genau einer Objektdatei benötigt, ist es nicht sinnvoll, diese Definition in der Klasse bereitzustellen, da Klassendefinitionen normalerweise in Header-Dateien vorhanden sind und in mehreren Objektdateien enthalten sind. Obwohl Sie in der Klasse einen Initialisierer bereitstellen können, müssen Sie dennoch das statische Datenelement irgendwo definieren.

Sie können es auch so betrachten, als würde man eine externVariable deklarieren:

namespace X {
  extern int i;
}

Dies deklariert die Variable, aber irgendwo im Programm muss eine Definition vorhanden sein:

int X::i = 0;
36
Jonathan Wakely

Sie müssen eine separate Definition für ein statisches Datenelement angeben (wenn sein odr-used wie in C++ 11 definiert ist), nur weil diese Definition irgendwo in einer und nur einer Übersetzungseinheit liegen soll. Statische Klassendatenelementmitglieder sind im Wesentlichen globale Objekte (globale Variablen), die im Klassenbereich deklariert sind. Der Compiler möchte, dass Sie eine bestimmte Übersetzungseinheit auswählen, die den eigentlichen "Körper" jedes globalen Objekts enthält. Sie müssen entscheiden, in welcher Übersetzungseinheit das eigentliche Objekt platziert werden soll.

7
AnT

Ein "statischer" Klassenmitglied ist wie eine global zugewiesene Variable (sie steht nicht in Zusammenhang mit der einzelnen Klasseninstanz), daher muss sie sich in einer Objektdatei befinden (und in der ".cpp" -Datei deklariert werden) als Symbol wie jedes andere Globale Variable.

Ein einfaches Klassenmitglied (nicht statisch) befindet sich in dem Speicherblock, der der Klasseninstanz zugeordnet ist.

3
Viktor Latypov

Der einfache Grund ist, dass Klassen normalerweise in header files deklariert werden, die häufig in mehreren cpp-Dateien enthalten sind. Statische Datenelemente haben eine externe Verknüpfung und müssen in genau einer Übersetzungseinheit deklariert werden, wodurch sie für die Definition innerhalb einer Klasse nicht geeignet sind.

Wie Juanchopanza darauf hinweist, ist Folgendes erlaubt:

struct A
{
    const static int i = 1;
};

Dies ist jedoch nur eine Deklaration keine Definition. Sie müssen sie noch definieren, wenn Sie die Adresse von i irgendwo verwenden möchten. Zum Beispiel:

f(int);
g(int&);

X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
2
Jesse Good

Beachten Sie, dass es möglich ist, das statische Datenelement an der Deklarationsstelle zu initialisieren, wenn es vom Typ const-Aufzählung vom Typ const-Aufzählung ist:

Aus dem C++ 03-Standard, §9.4.2

Wenn ein statischer Datenmember vom Typ const integral oder const ist, kann seine Deklaration in der Definition der Klasse Einen Konstanteninitialisierer angeben, der ein integraler Konstantenausdruck sein soll (5.19).

struct Foo {
  static const int j = 42; // OK
};
1
juanchopanza

Wenn der Compiler aus einer Unit Binärcode generiert (extreme Vereinfachung: eine cpp-Datei und alle enthaltenen Header), gibt er ein Symbol für die statische Variable und schließlich den Initialisierungscode für diese Variable aus.

Es ist in Ordnung, dass ein statisches Variablensymbol in mehreren Einheiten deklariert wird, es ist jedoch nicht in Ordnung, dass es mehrmals initialisiert wird.

Sie müssen also sicherstellen, dass der Initialisierungscode nur für eine einzelne Einheit ausgegeben wird. Dies bedeutet, dass die statische Variable in genau einer Einheit definiert werden muss.

1
Gigi

Static Data Member

#include<iostream.h>
#include<conio.h>

class static_var
{

static int count; //static member of class
public :

void incr_staticvar()
{
count++;
}

void outputc()
{ 
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};

int static_var::count;

void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;

obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();

cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";

obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );

getch();
}
0