
Pfund.
Ich hätte gerne eine private statische Konstante für eine Klasse (in diesem Fall eine Shape-Factory).
Ich hätte gerne so etwas.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Leider bekomme ich alle möglichen Fehler vom C++ (g++) Compiler, wie zum Beispiel:
ISO C++ verbietet die Initialisierung des Members ‘RECTANGLE’
ungültige In-Class-Initialisierung des statischen Datenmembers des nicht ganzzahligen Typs „std::string“
Fehler: ‘RECTANGLE’ statisch machen
Dies sagt mir, dass diese Art von Mitgliedsdesign nicht mit dem Standard konform ist. Wie haben Sie eine private Literalkonstante (oder vielleicht eine öffentliche), ohne eine #define-Direktive verwenden zu müssen (ich möchte die Hässlichkeit der Datenglobalität vermeiden!)
Jede Hilfe ist willkommen.

Ameise
Sie müssen Ihr statisches Mitglied außerhalb der Klassendefinition definieren und dort den Initialisierer bereitstellen.
Zuerst
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
und dann
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
Die Syntax, die Sie ursprünglich verwenden wollten (Initialisierer innerhalb der Klassendefinition), ist nur mit Ganzzahl- und Aufzählungstypen zulässig.
Ab C++17 haben Sie eine weitere Möglichkeit, die Ihrer ursprünglichen Deklaration sehr ähnlich ist: Inline-Variablen
// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};
Es ist keine zusätzliche Definition erforderlich.
Ab C++20 statt const
du kannst es deklarieren constexpr
bei dieser Variante. Explizit inline
wäre nicht mehr nötig, da constexpr
impliziert inline
.
In C++11 können Sie jetzt Folgendes tun:
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
Innerhalb von Klassendefinitionen können Sie nur erklären statische Mitglieder. Sie müssen definiert außerhalb der Klasse. Für integrale Konstanten zur Kompilierzeit macht der Standard die Ausnahme, dass Sie Mitglieder “initialisieren” können. Es ist aber immer noch keine Definition. Ohne Definition würde zum Beispiel die Adressaufnahme nicht funktionieren.
Ich möchte erwähnen, dass ich keinen Vorteil darin sehe, std::string gegenüber const char zu verwenden[] für Konstanten. std::string ist nett und alles, aber es erfordert eine dynamische Initialisierung. Also, wenn du so etwas schreibst
const std::string foo = "hello";
Auf Namensraumebene wird der Konstruktor von foo direkt vor der Ausführung von main ausgeführt, und dieser Konstruktor erstellt eine Kopie der Konstante “hello” im Heap-Speicher. Sofern Sie nicht wirklich RECTANGLE als std::string benötigen, könnten Sie genauso gut schreiben
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
Dort! Keine Heap-Zuordnung, kein Kopieren, keine dynamische Initialisierung.
Tschüss, s.
In C++ 17 können Sie verwenden Inline-Variablen:
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
Beachten Sie, dass sich dies von der Antwort von abyss.7 unterscheidet: Diese definiert eine tatsächliche std::string
Objekt, nicht a const char*
Dies sind nur zusätzliche Informationen, aber wenn Sie die Zeichenfolge wirklich in einer Header-Datei haben möchten, versuchen Sie Folgendes:
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
Obwohl ich bezweifle, dass das empfohlen wird.
Die statischen Variablen der Klasse können sein erklärt in der Kopfzeile muss aber sein definiert in einer .cpp-Datei. Dies liegt daran, dass es nur eine Instanz einer statischen Variablen geben kann und der Compiler nicht entscheiden kann, in welche generierte Objektdatei sie eingefügt werden soll, sodass Sie stattdessen die Entscheidung treffen müssen.
Um die Definition eines statischen Werts bei der Deklaration in C++11 beizubehalten, kann eine verschachtelte statische Struktur verwendet werden. In diesem Fall ist das statische Element eine Struktur und muss in einer .cpp-Datei definiert werden, aber die Werte befinden sich im Header.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Anstatt einzelne Mitglieder zu initialisieren, wird die gesamte statische Struktur in .cpp initialisiert:
A::_Shapes A::shape;
Der Zugriff auf die Werte erfolgt mit
A::shape.RECTANGLE;
oder – da die Mitglieder privat sind und nur von A verwendet werden sollen – mit
shape.RECTANGLE;
Beachten Sie, dass diese Lösung immer noch unter dem Problem der Initialisierungsreihenfolge der statischen Variablen leidet. Wenn ein statischer Wert verwendet wird, um eine andere statische Variable zu initialisieren, ist die erste möglicherweise noch nicht initialisiert.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In diesem Fall die statische Variable Kopfzeilen enthält entweder { “” } oder { “.h”, “.hpp” }, abhängig von der vom Linker erstellten Initialisierungsreihenfolge.
Wie von @abyss.7 erwähnt, könnten Sie auch verwenden constexpr
wenn der Wert der Variablen zur Kompilierzeit berechnet werden kann. Aber wenn du deine Saiten mit deklarierst static constexpr const char*
und Ihr Programm verwendet std::string
sonst gibt es einen Mehraufwand, weil ein neues std::string
-Objekt wird jedes Mal erstellt, wenn Sie eine solche Konstante verwenden:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}

aJ.
Um diese In-Class-Initialisierungssyntax zu verwenden, muss die Konstante eine statische Konstante vom Typ Ganzzahl oder Aufzählung sein, die durch einen konstanten Ausdruck initialisiert wird.
Dies ist die Einschränkung. Daher müssen Sie in diesem Fall eine Variable außerhalb der Klasse definieren. siehe Antwort von @AndreyT
9857000cookie-checkStatische Konstante Zeichenfolge (Klassenmitglied)yes
Kann mir bitte jemand sagen, was ein “integraler” Typ ist? Danke sehr.
– Pfund.
16. Oktober 2009 um 13:43 Uhr
Ganzzahlige Typen beziehen sich auf Typen, die ganze Zahlen darstellen. Sehen publib.boulder.ibm.com/infocenter/comphelp/v8v101/…
– Bläser
27. Juli 2012 um 4:37 Uhr
Ein privater statischer String in Ihrer Factory ist keine gute Lösung – bedenken Sie, dass Ihre Factory-Clients wissen müssen, welche Formen unterstützt werden, also legen Sie sie in einem separaten Namespace als static const std::string RECTANGLE = “Rectangle “.
– LukeCodeBaker
9. Januar 2016 um 22:15 Uhr
Wenn Ihre Klasse eine Vorlagenklasse ist, siehe stackoverflow.com/q/3229883/52074
– Trevor Boyd Smith
9. Juli 2018 um 12:50 Uhr