2014-04-04 3 views
8

So lassen Sie uns sagen, dass ich einen Header wie dieses:Warum sollte ich statische Variable im Header nicht initialisieren?

#ifndef BASECLASS_H 
#define BASECLASS_H 

class BaseClass 
{ 
    public: 
     static int getX(){return x;} 
    private: 
     static int x; 
}; 

int BaseClass::x = 10; 

#endif 

ich viele Male gehört haben, dass ich nicht statische Variablen in einem Header, sondern in cpp initialisieren sollte. Aber da es Wachen gibt, sollte es nur eine Kopie von BaseClass :: x geben. So verstehe ich irgendwie nicht, warum ich

int BaseClass::x = 10; 

in cpp setzen sollte. Vielen Dank.

+0

Die Frage Phrasierung und Antworten hier sind besser als die in der nominierten Frage! –

Antwort

9

Wenn Sie dies in der Kopfzeile tun, erhalten Sie mehrere Definitionsfehler, sobald Sie sie aus mehr als einer CPP-Datei einfügen. Sie sagen dem Compiler wirklich zwei Dinge, wenn Sie erklären:

int BaseClass::x = 10; 

Zuerst definieren Sie das Symbol BaseClass :: x; 2. Sie sagen, dass Sie wollen, dass es den Anfangswert von 10 hat. Nach dem kann dies nur einmal in Ihrem Programm passieren.

+0

Ich denke ich fange an, die Idee zu bekommen, aber gibt es eine Möglichkeit, es zu demonstrieren? Ist es, dass ich zwei verschiedene Programme schreiben muss, die BaseClass einschließen und sie gleichzeitig laufen lassen? – user3496846

+2

@ user3496846 Nein, Sie brauchen nur ein einzelnes Programm, bestehend aus (mindestens) zwei cpp-Dateien, die beide Ihre Kopfzeile enthalten. –

2

Da, wenn Sie es in der Kopfzeile initialisieren, besteht die Möglichkeit, dass es an mehreren Stellen definiert wäre, wenn Sie die Kopfzeile mehr als einmal einschließen. Dies führt zu einem Linker-Fehler

4

Die Wächter verhindern nicht mehrere Kopien in mehreren Quelldateien. Sie verhindern nur mehrere Kopien in einer Quelldatei.

Sie verstoßen gegen die eine Definitionsregel, wenn Sie mehrere Quelldateien haben, die #include "base_class.h".

4

Vielleicht ist es einfacher zu verstehen, wenn Sie darüber nachdenken, was der Präprozessor tatsächlich tut: Er kopiert den Inhalt aller enthaltenen Header-Dateien in die cpp-Datei und übergibt diese an den Compiler.

Lassen Sie uns jetzt sagen, Sie haben:

// In a.cpp 
#include <baseclass.h> 

// more code 

// In b.cpp 
#include <baseclass.h> 

// more code 

Nach der Präprozessor erweitert das enthält, werden beide Dateien enthalten:

int BaseClass::x = 10; 

Jetzt, sobald beide Objektdateien an den Linker übergeben werden, es wird das Symbol BaseClass::x zweimal sehen - was ein Fehler ist.

Jetzt ist es noch deutlicher zu machen, stellen Sie sich dies in einer Header-Datei setzen würde:

int aGlobalVariable = 10; 

Und dann sind sie in zwei verschiedenen CPP-Dateien, die beide in eine ausführbare Datei verknüpft werden soll. Es ist eigentlich nicht anders als Ihr Beispiel, wenn man es aus der Sicht des Linkers betrachtet.

Warum ist dies kein Problem mit Klassendeklarationen?

Es gibt einen Unterschied zwischen Erklärungen und Definitionen. Nur letzteres wird Probleme verursachen. Z.B., Alle folgenden sind Erklärungen:

  • extern int a;
  • void foo(int a);
  • class Foo { int bar(); };

Während diese sind Definitionen:

  • int a;
  • int b = 10;
  • void foo(int a) { /*..*/ }
  • int Foo::bar() { /*...*/ }

Solange es ist (und man nur) Definition, können Sie so viele Erklärungen haben, wie Sie möchten, und die Linke wird sicherstellen, dass sie alle beziehen sich auf die gleiche Funktion oder Speicherstelle.

Nun, was ist mit Klassen? Klassen können nur deklariert werden, während ihre Elementfunktionen und statischen Mitglieder definiert werden müssen. Auch hier kann jede Definition nur einmal vorkommen.

Memberfunktionen und statische Member sind tatsächlich nur einmal im Adressraum eines Programms vorhanden, während normale Member (Instanzvariablen) für jedes Objekt der Klasse existieren.

Zurück zu Ihrem spezifischen Problem: statische Mitglieder sind im Grunde nur globale Variablen, aber auf den Klassennamen beschränkt.

Hoffe, dass dies die Dinge für Sie aufräumt!

+0

Aber enthält der Linker neben der #include "baseClass.h" nicht auch die doppelte Definition der Klasse selbst, was ebenfalls ein Problem verursachen sollte? Entschuldigung, es kann einige Zeit dauern, bis ich es verstanden habe ... – user3496846

+0

Nein, weil es nur eine Klasse * Deklaration * ist. Ich werde ein wenig darüber zu meiner Antwort hinzufügen –

+0

OK, vielen Dank für solch eine beschreibende Antwort, ich denke, ich fange an, die Idee zu bekommen :) – user3496846

Verwandte Themen