Warum kann ich static
Datenelemente in der Klasse nicht initialisieren ?
Mit dem C ++ - Standard können nur statische Konstantenintegral- oder Aufzählungstypen innerhalb der Klasse initialisiert werden. Dies ist der Grund, warum a
die Initialisierung zulässig ist, während andere dies nicht tun.
Referenz:
C ++ 03 9.4.2 Statische Datenelemente
§4
Wenn ein statisches Datenelement vom Typ const Integral oder vom Typ const enumeration ist, kann seine Deklaration in der Klassendefinition einen Konstanteninitialisierer angeben, der ein integraler konstanter Ausdruck sein soll (5.19). In diesem Fall kann das Element in ganzzahligen konstanten Ausdrücken erscheinen. Das Mitglied muss weiterhin in einem Namespace-Bereich definiert sein, wenn es im Programm verwendet wird, und die Namespace-Bereichsdefinition darf keinen Initialisierer enthalten.
Was sind integrale Typen?
C ++ 03 3.9.1 Grundtypen
§7
Die Typen bool, char, wchar_t sowie die vorzeichenbehafteten und vorzeichenlosen Ganzzahltypen werden zusammen als integrale Typen bezeichnet.43) Ein Synonym für integralen Typ ist der ganzzahlige Typ.
Fußnote:
43) Daher sind die Aufzählungen (7.2) nicht ganzzahlig; Aufzählungen können jedoch auf int, unsigned int, long oder unsigned long heraufgestuft werden, wie in 4.5 angegeben.
Problemumgehung:
Mit dem Enum-Trick können Sie ein Array in Ihrer Klassendefinition initialisieren.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Warum erlaubt der Standard dies nicht?
Bjarne erklärt dies hier treffend :
Eine Klasse wird normalerweise in einer Header-Datei deklariert, und eine Header-Datei ist normalerweise in vielen Übersetzungseinheiten enthalten. Um jedoch komplizierte Linkerregeln zu vermeiden, erfordert C ++, dass jedes Objekt eine eindeutige Definition hat. Diese Regel würde verletzt, wenn C ++ die Definition von Entitäten in der Klasse zulässt, die als Objekte im Speicher gespeichert werden müssen.
Warum sind nur static const
integrale Typen und Aufzählungen in der Klasseninitialisierung zulässig?
Die Antwort ist in Bjarnes Zitat verborgen. Lesen Sie es genau durch:
"C ++ erfordert, dass jedes Objekt eine eindeutige Definition hat. Diese Regel würde verletzt, wenn C ++ die Definition von Entitäten in der Klasse zulässt, die als Objekte im Speicher gespeichert werden müssen."
Beachten Sie, dass nur static const
Ganzzahlen als Konstanten für die Kompilierungszeit behandelt werden können. Der Compiler weiß, dass sich der ganzzahlige Wert zu keiner Zeit ändert und daher seine eigene Magie anwenden und Optimierungen anwenden kann. Der Compiler fügt solche Klassenmitglieder einfach ein, dh sie werden nicht mehr im Speicher gespeichert, da die Notwendigkeit, im Speicher gespeichert zu werden, beseitigt wird gibt es solchen Variablen die Ausnahme von der von Bjarne erwähnten Regel.
Hierbei ist zu beachten, dass selbst wenn static const
Integralwerte eine In-Class-Initialisierung aufweisen können, die Adressierung solcher Variablen nicht zulässig ist. Man kann die Adresse eines statischen Mitglieds nehmen, wenn (und nur wenn) es eine Definition außerhalb der Klasse hat. Dies bestätigt die obige Argumentation weiter.
Aufzählungen sind zulässig, da Werte eines Aufzählungstyps verwendet werden können, wenn Ints erwartet werden. siehe Zitat oben
Wie ändert sich dies in C ++ 11?
C ++ 11 lockert die Einschränkung bis zu einem gewissen Grad.
C ++ 11 9.4.2 Statische Datenelemente
§3
Wenn ein statisches Datenelement vom Typ const literal ist, kann seine Deklaration in der Klassendefinition einen Klammer-oder-Gleich-Initialisierer angeben, in dem jede Initialisierer-Klausel , die ein Zuweisungsausdruck ist, ein konstanter Ausdruck ist. Ein statisches Datenelement vom Typ Literal kann in der Klassendefinition mit dem constexpr specifier;
wenn ja deklariert werden. In seiner Deklaration muss ein Klammer-oder-Gleich-Initialisierer angegeben werden, in dem jede Initialisierer-Klausel ein Zuweisungsausdruck istist ein konstanter Ausdruck. [Hinweis: In beiden Fällen kann das Mitglied in konstanten Ausdrücken erscheinen. —End note] Das Mitglied muss weiterhin in einem Namespace-Bereich definiert sein, wenn es im Programm verwendet wird, und die Definition des Namespace-Bereichs darf keinen Initialisierer enthalten.
Auch C ++ 11 wird ermöglichen (§12.6.2.8) ein nicht-statisches Datenelement initialisiert werden , wo sie (in dieser Klasse) deklariert wird. Dies bedeutet eine sehr einfache Benutzersemantik.
Beachten Sie, dass diese Funktionen in der neuesten Version 4.7 noch nicht implementiert wurden. Daher werden möglicherweise immer noch Kompilierungsfehler angezeigt.