Statische Konstante Zeichenfolge (Klassenmitglied)

Lesezeit: 8 Minuten

Statische Konstante Zeichenfolge Klassenmitglied
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.

  • 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


Statische Konstante Zeichenfolge Klassenmitglied
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.

  • Wenn es nicht erforderlich ist, einen STL-String zu verwenden, können Sie auch einfach ein const char* definieren. (weniger Overhead)

    – KSchmidt

    14. Oktober 2009 um 2:23 Uhr

  • Ich bin mir nicht sicher, ob es immer weniger Aufwand ist – es hängt von der Nutzung ab. Wenn dieser Member als Argument an Funktionen übergeben werden soll, die die konstante Zeichenfolge & annehmen, wird während der Initialisierung für jeden Aufruf temporär erstellt, im Gegensatz zur Erstellung eines Zeichenfolgenobjekts. IMHO Overhead für die Erstellung eines statischen String-Objekts ist vernachlässigbar.

    – Tadeusz Kopec für die Ukraine

    14. Oktober 2009 um 12:49 Uhr

  • Ich würde auch lieber ständig std::string verwenden. Der Overhead ist vernachlässigbar, aber Sie haben viel mehr Optionen und es ist viel unwahrscheinlicher, dass Sie dumme Dinge wie “magic” == A::RECTANGLE schreiben, nur um ihre Adresse zu vergleichen …

    – Matthias M.

    14. Oktober 2009 um 14:24 Uhr

  • der char const* hat den Vorteil, dass es initialisiert wird, bevor die gesamte dynamische Initialisierung abgeschlossen ist. Sie können sich also auf den Konstruktor eines beliebigen Objekts verlassen RECTANGLE damals schon initialisiert worden sein.

    – Johannes Schaub – litb

    16. Oktober 2009 um 11:40 Uhr

  • @cirosantilli: Weil von Anfang an in C++ Initialisierer enthalten waren Definitionennicht Erklärungen. Und die Deklaration von Datenelementen innerhalb der Klasse ist genau das: eine Deklaration. (Andererseits wurde eine Ausnahme für const integrale und enum-Member gemacht, und in C++11 – für const-Member von wörtlich Typen.)

    – Ant

    10. Januar 2013 um 16:24 Uhr

In C++11 können Sie jetzt Folgendes tun:

class A {
 private:
  static constexpr const char* STRING = "some useful string constant";
};

  • Leider funktioniert diese Lösung nicht für std::string.

    – Kleines Schach

    27. Oktober 2015 um 5:51 Uhr

  • Beachten Sie, dass 1. dies nur mit Literalen funktioniert und 2. dies nicht standardkonform ist, obwohl Gnu/GCC Bußgelder kompiliert, andere Compiler einen Fehler werfen. Definition muss im Körper sein.

    – ManuelSchneid3r

    16. November 2015 um 11:40 Uhr

  • @ManuelSchneid3r Wie genau ist das “nicht normgerecht”? Es sieht aus wie Moor-Standard-C++11 Klammer-oder-Gleich-Initialisierung mir.

    – Unterstrich_d

    10. Februar 2016 um 11:24 Uhr

  • @rvighne, nein das ist falsch. constexpr impliziert const für var, nicht für type it points. Dh static constexpr const char* const ist das gleiche wie static constexpr const char*aber nicht dasselbe wie static constexpr char*.

    – midenok

    11. August 2016 um 14:46 Uhr

  • @abyss.7 – Danke für deine Antwort, und ich habe bitte noch eine: Warum muss es statisch sein?

    – Guy Avraham

    6. November 2017 um 6:55 Uhr

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.

  • Dies ist eine Pre-C++ 11-Antwort. Verwenden Sie Standard-C++ und verwenden Sie std::string_view.

    Benutzer10133158

    25. Oktober 2018 um 7:55 Uhr


  • C++11 hat kein std::string_view.

    – Lukas Salich

    8. April 2019 um 15:03 Uhr

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.

  • Das sieht cool aus 🙂 – Ich vermute, Sie haben einen Hintergrund in anderen Sprachen als C++?

    – Pfund.

    16. Oktober 2009 um 13:41 Uhr

  • Ich würde es nicht empfehlen. Ich mache das häufig. Es funktioniert gut und ich finde es offensichtlicher, als die Zeichenfolge in die Implementierungsdatei einzufügen. Die eigentlichen Daten von std::string befinden sich jedoch immer noch auf dem Heap. Ich würde ein const char* zurückgeben, in diesem Fall müssen Sie die statische Variable nicht deklarieren, damit die Deklaration weniger Platz benötigt (codeweise). Allerdings nur Geschmackssache.

    – Zoomulator

    18. Juni 2012 um 18:27 Uhr


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.
}

  • Das sieht cool aus 🙂 – Ich vermute, Sie haben einen Hintergrund in anderen Sprachen als C++?

    – Pfund.

    16. Oktober 2009 um 13:41 Uhr

  • Ich würde es nicht empfehlen. Ich mache das häufig. Es funktioniert gut und ich finde es offensichtlicher, als die Zeichenfolge in die Implementierungsdatei einzufügen. Die eigentlichen Daten von std::string befinden sich jedoch immer noch auf dem Heap. Ich würde ein const char* zurückgeben, in diesem Fall müssen Sie die statische Variable nicht deklarieren, damit die Deklaration weniger Platz benötigt (codeweise). Allerdings nur Geschmackssache.

    – Zoomulator

    18. Juni 2012 um 18:27 Uhr


1646879413 353 Statische Konstante Zeichenfolge Klassenmitglied
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

985700cookie-checkStatische Konstante Zeichenfolge (Klassenmitglied)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy