2016-01-17 5 views
9

Ich verstehe nicht, warum C++ nur ganzzahlige Typen erlaubt und enum (enum ist auch ein ganzzahliger Typ) innerhalb einer Klassendeklaration zu definieren. Alle anderen Typen, einschließlich Float Point-Typen (d. H. Double und Float) müssen außerhalb der Klassendeklaration definiert werden. Natürlich muss das ein Grund dafür sein, aber ich kann es nicht herausfinden.Warum nur integral oder enum-Typ in einer C++ - Klasse initialisiert werden kann?

Code-Beispiel:

#include <iostream> 

using namespace std; 

struct Node { 

    static const int c = 0; // Legal Definition 
    static const long l = 0l; // Legal Definition 
    static const short s = 0; // Legal Definition 

    static const float f = 0.0f; // Illegal definition 
    static const string S = "Test"; // Illegal definition 

    static const string JOB_TYPE; // Legal declaration 
    static const float f; // Legal declaration 
    static const double d; // Legal declaration 
}; 

const string Node::JOB_TYPE = "Test"; // correct definition 
const float Node::f = 0.0f; // correct definition 
const double Node::d = 0.0; // correct definition 

int main() { 

    cout << Node::c << endl; 
    cout << Node::c << endl; 

    cout << Node::JOB_TYPE << endl; 

    cout << Node::f << endl; 

} 
+0

Sie haben nur Probleme, wenn Sie die 'Node' Struktur in eine Kopfzeile einfügen und Sie in 2 Dateien einschließen. –

+1

Das ist eine sehr gute Frage - Habe meine Gehirnzellen diesen Sonntag rattern lassen. Danke –

+2

Besondere Regeln für Floating-Point sind in der Regel wegen Bedenken über Cross-Compiler, dh Compiler, die auf einem System ausgeführt werden, aber Code für einen anderen generieren. Es ist einfach genug, mit integrierten Typen zu arbeiten, die dem Zielsystem entsprechen. Die Details der Gleitkommatypen eines anderen Systems zu erhalten, ist viel komplizierter. –

Antwort

8

Der Hauptgrund ist hier, dass integrale Typen (und enum weil innerhalb der Compiler dieser ganzen Zahlen irgendeine Art werden) trivialer ersetzt werden können und direkt als Konstanten verwendet. Wenn der Compiler S::x sieht, kann er sofort durch die Konstante 42 im generierten Code ersetzt werden. Dasselbe gilt nicht (immer) für float und schon gar nicht für herstellerabhängige Typen wie std::string - der Compiler kann keinen Speicher für std::string ohne Aufruf von new (oder std::string::allocator) zuweisen. Also für Konstanten, die "konstruiert" werden müssen und/oder komplexere Kriterien haben, wie sie verwendet werden können (man denke an einen Prozessor, der keine Hardwareunterstützung für Fließkommafunktionsaufrufe zum Laden und Speichern von Fließkommawerten hat, usw.), die Sprache kann nicht vorschreiben, dass dies erlaubt sein sollte.

Wenn Sie die struct Node Deklaration mit static const std::string S = "test"; einschließen, wie viele Orte sollte der Compiler Node::S in? Welchen sollte es verwenden, wenn es schließlich Ihre drei Übersetzungseinheiten zu einem Programm verknüpft - oder sollte es andere verwenden? Was passiert dann, wenn Sie const_cast die Node::S ändern und ändern? Letzteres setzt voraus, dass Sie eine Umgebung haben, in der dies keinen Absturz verursacht, was völlig plausibel ist, und obwohl dies ein undefiniertes Verhalten ist, bin ich nicht sicher, ob der Compiler es so komisch machen sollte, unterschiedliche Werte in jeder Übersetzungseinheit zu verwenden Dieser Fall ...

Edit: Wie in den Kommentaren erwähnt, erlaubt C++ 11 weitere Typen in ähnlicher Weise verwendet werden, so dass die Einschränkungen gelockert werden, da Compiler und Hardware-Technologie verbessert wird. Ich bezweifle, Sie jemals static const std::map<X, Y> a = { ... } tho ', wie das ist ein ziemlich komplexer Datentyp zu konstruieren ...

+0

"Der Hauptgrund hier ist, dass integrale Typen (und enum, weil innerhalb des Compilers diese zu ganzen Zahlen werden) trivial ersetzt werden und direkt als Konstanten verwendet werden können." Im Allgemeinen können literale Typen verwendet werden Weg - vielleicht können wir hoffen, dass die Regel entspannt wird, um diese einzuschließen? –

+0

Nun, das Problem ist, dass Literale auch Gleitkommazahlen sein können [nicht sicher, ob es auch andere gibt], und sie erfordern oft eine spezielle Behandlung - insbesondere auf Hardware, die keine eingebaute Unterstützung für Fließkomma hat. –

+1

@ChrisBeck "wird entspannt sein" -> "sind entspannt". http://melpon.org/wandbox/permlink/1qxlfeqKMVWoeti7 und allgemeiner alle literalen Typen, [class.static.data] p3 – dyp

0

Initialisierung von std::string erfordert einige Code zur Laufzeit ausgeführt werden.

Das Initialisieren eines Zeigers mit Zeichenfolgenliteral erfordert das Platzieren der Zeichenfolge in dem Speicher auch in Laufzeit.