Statische Funktion deklariert, aber nicht in C ++ definiert

74

Ich erhalte eine Fehlermeldung aus dem folgenden Code mit C ++.

Main.cpp

#include "file.h"

int main()
{
   int k = GetInteger();
   return 0;
}

File.h

static int GetInteger();

File.cpp

#include "file.h"

static int GetInteger()
{
   return 1;
}

Der Fehler, den ich bekomme:

Error C2129: static function 'int GetInteger(void)' declared but not defined.

Ich habe den berühmten Artikel "Organisieren von Codedateien in C und C ++" gelesen , verstehe aber nicht, was mit diesem Code falsch ist.

Sait
quelle
2
Wie verlinkst du es? "gcc -o Test Main.cpp File.cpp -lstdc ++" oder irgendwo in XCode / VisualStudio / Eclipse?
Viktor Latypov
2
Was @ViktorLatypov gesagt hat. Zeigen Sie uns, wie Sie es kompilieren.
Brady
@ViktorLatypov: Ich stoße darauf, indem ich die Datei in Visual Studio 2013 in einem C ++ / CLI-Projekt auswähle und auf die Schaltfläche zum Kompilieren klicke. (Die Kompilierungsschaltfläche für eine C ++ - Schaltfläche ist nicht verknüpft und sollte nicht auf diesen Fehler stoßen, aber vielleicht ist C ++ / CLI anders?) (Oh, warte, habe gerade die beste Antwort gesehen. Ich habe eine staticKlasse in einen Namespace konvertiert >. <
Vergessen

Antworten:

128

In C ++ bedeutet staticim globalen / Namespace-Bereich, dass die Funktion / Variable nur in der Übersetzungseinheit verwendet wird, in der sie definiert ist, nicht in anderen Übersetzungseinheiten.

Hier versuchen Sie, eine statische Funktion aus einer anderen Übersetzungseinheit ( Main.cpp) als der zu verwenden, in der sie definiert ist ( File.cpp).

Entfernen Sie die staticund es sollte gut funktionieren.

HighCommander4
quelle
23

Veränderung

static int GetInteger();

zu

int GetInteger();

staticIn diesem Fall gibt die Methode die interne Verknüpfung an , dh Sie können sie nur in der Übersetzungseinheit verwenden, in der Sie sie definieren.

Sie definieren es in File.cppund versuchen, es in zu verwenden main.cpp, aber main hat keine Definition dafür, da Sie es deklariert haben static.

Luchian Grigore
quelle
6

Denn in diesem Fall staticbedeutet dies, dass der Name der Funktion eine interne Verknüpfung aufweist. dass GetIntegerin einer Übersetzungseinheit nichts mit GetIntegereiner anderen Übersetzungseinheit zu tun hat. Das Schlüsselwort staticist überladen: In einigen Fällen wirkt es sich auf die Lebensdauer und in anderen auf die Bindung aus. Dies ist hier besonders verwirrend, da "statisch" auch der Name Ihres Lebens ist. Funktionen und Daten, die im Namespace-Bereich deklariert wurden, haben immer eine statische Lebensdauer. Wenn es staticin ihrer Deklaration erscheint, verursacht es eine interne Bindung anstelle einer externen.

James Kanze
quelle
3

Funktionen, die als statisch deklariert sind, befinden sich in der enthaltenen Datei. Daher müssen Sie die Funktion in derselben Datei definieren wie diejenigen, die sie aufrufen. Wenn Sie es aus einer anderen Datei aufrufbar machen möchten, dürfen Sie es NICHT als statisch deklarieren.

LeleDumbo
quelle
2

Nach meinem Verständnis werden statische Funktionen mit dem Dateinamen, in dem sie definiert sind, entstellt. Wenn Sie also file.h in main.cpp einfügen, wird GetInteger () mit main.cpp entstellt, obwohl Sie GetInteger () in file.cpp definiert haben Da es statisch ist, wird es auch entstellt und der Linker kann die Definition von GetInteger () nicht finden, da keine Funktion mit diesem Namen vorhanden ist.

Ich glaube, die gewonnene Erkenntnis ist, dass statische Funktionen in der Header-Datei nicht deklariert werden, da sie nicht als Teil der Schnittstelle gedacht sind.

HBY4PI
quelle
2

Wenn sich alles in derselben Übersetzungseinheit befindet, sollte es funktionieren. Sie haben File.cpp wahrscheinlich nicht in derselben Einheit wie Main.cpp kompiliert.

g++ -Wall File.cpp Main.cpp

Wenn jede Datei separat kompiliert wird, muss die Funktion externvon einer anderen Übersetzungseinheit verwendet werden.

extern int GetInteger();

das ist das gleiche wie

int GetInteger();
log0
quelle
Er benutzt Visual Studio, nicht g ++
Brady
0

Erwägen Sie die Verwendung von Namespaces ...

für logische Codeabschnitte, für die keine internen Elementvariablen erforderlich sind. Das heißt, für Ihre GetInteger()Funktion muss keine interne Konstantenvariable referenziert werden. Verwenden Sie Namespaces, um Ihre Funktionen in Ihrem Code zu organisieren. Dies verhindert, dass Funktionsnamen in Konflikt geraten (was Ihnen stundenlange Kopfschmerzen mit möglichen LNKFehlern erspart). Der Code funktioniert weiterhin so, wie Sie ihn eingerichtet haben, und funktioniert weiterhin innerhalb der Grenzen der akzeptierten Antwort. Darüber hinaus kann Ihnen Ihr Namespace-Name beim schnellen Debuggen helfen.

Main.cpp

#include "file.h"

int main()
{
   int k = HELPERS::GetInteger();
   return 0;
}

File.h

namespace HELPERS
{
    int GetInteger();
}

File.cpp

#include "file.h"

int HELPERS::GetInteger()
{
   return 1;
}
Andrew
quelle