Nierozwiązany symbol zewnętrzny na statycznych elementach członkowskich

132

Mówiąc najprościej:

Mam klasę, która składa się głównie ze statycznych publicznych elementów członkowskich, więc mogę grupować razem podobne funkcje, które nadal muszą być wywoływane z innych klas / funkcji.

W każdym razie zdefiniowałem dwie statyczne zmienne typu unsigned char w zakresie publicznym mojej klasy, kiedy próbuję zmodyfikować te wartości w konstruktorze tej samej klasy, podczas kompilacji pojawia się błąd „nierozwiązany symbol zewnętrzny”.

class test 
{
public:
    static unsigned char X;
    static unsigned char Y;

    ...

    test();
};

test::test() 
{
    X = 1;
    Y = 2;
}

Jestem nowy w C ++, więc nie przejmuj się. Dlaczego nie mogę tego zrobić?

Austin W.Bryan
źródło

Odpowiedzi:

149

Jeśli używasz C ++ 17 , możesz po prostu użyć inlinespecyfikatora (patrz https://stackoverflow.com/a/11711082/55721 )


Jeśli używasz starszych wersji standardu C ++, musisz dodać definicje, aby pasowały do ​​deklaracji X i Y

unsigned char test::X;
unsigned char test::Y;

gdzieś. Możesz również zainicjować statyczny element członkowski

unsigned char test::X = 4;

i znowu, robisz to w definicji (zwykle w pliku CXX), a nie w deklaracji (która często jest w pliku .H)

Colin Jensen
źródło
5
Jeśli piszesz bibliotekę tylko z nagłówkami, możesz użyć tej techniki, aby uniknąć pliku cpp: stackoverflow.com/questions/11709859/…
Shital Shah
64

Deklaracje składowych danych statycznych w deklaracji klasy nie są ich definicją. Aby je zdefiniować, należy to zrobić w .CPPpliku, aby uniknąć powielania symboli.

Jedyne dane, które można zadeklarować i zdefiniować, to integralne stałe statyczne. (Wartości od enumsmogą być również używane jako wartości stałe)

Możesz przepisać swój kod jako:

class test {
public:
  const static unsigned char X = 1;
  const static unsigned char Y = 2;
  ...
  test();
};

test::test() {
}

Jeśli chcesz mieć możliwość modyfikowania zmiennych statycznych (innymi słowy, gdy deklarowanie ich jako stałych jest niewłaściwe), możesz oddzielić swój kod między .Hi .CPPw następujący sposób:

.H:

class test {
public:

  static unsigned char X;
  static unsigned char Y;

  ...

  test();
};

.CPP:

unsigned char test::X = 1;
unsigned char test::Y = 2;

test::test()
{
  // constructor is empty.
  // We don't initialize static data member here, 
  // because static data initialization will happen on every constructor call.
}
sergtk
źródło
dlaczego tutaj w .CPP jest to "test bez znaku :: X = 1;" zamiast "test :: X = 1;"? zmienna statyczna X już zdefiniowana, po co nadal potrzebny jest znak „bez znaku”? @sergtk
Penny
@Penny Ponieważ "test :: X = 1;" jest interpretowane jako zadanie, podczas gdy to, co próbujemy zrobić, to definicja.
Anonymous
5

Ponieważ jest to pierwszy wątek SO, który pojawił się podczas wyszukiwania „nierozwiązanych zewnętrznych elementów ze statycznymi elementami stałymi”, zostawię tutaj kolejną wskazówkę dotyczącą rozwiązania jednego problemu z nierozwiązanymi zewnętrznymi elementami:

Dla mnie zapomniałem o zaznaczeniu definicji mojej klasy __declspec(dllexport), a gdy zostałem wywołany z innej klasy (poza granicami biblioteki DLL tej klasy), oczywiście otrzymałem nierozwiązany błąd zewnętrzny.
Mimo to, łatwo jest zapomnieć, kiedy zmieniasz wewnętrzną klasę pomocniczą na taką, która jest dostępna z innego miejsca, więc jeśli pracujesz w dynamicznie połączonym projekcie, równie dobrze możesz to sprawdzić.

Johann Studanski
źródło
4

w moim przypadku zadeklarowałem jedną zmienną statyczną w pliku .h, na przykład

//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}

aw myClass.cpp próbowałem użyć tego m_nMyVar. Wystąpił błąd LINK, taki jak:

błąd LNK2001: nierozwiązany symbol zewnętrzny „public: klasa statyczna ... Plik cpp powiązany z błędem łącza wygląda następująco:

//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}

Więc dodaję poniższy kod na górze myClass.cpp

//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}

wtedy LNK2001 zniknie.

Grosz
źródło
0

W moim przypadku użyłem złego linkowania.
Był zarządzany C ++ (CLI), ale z natywnym eksportowaniem. Dodałem do linkera -> dane wejściowe -> zasób łącza zestawu dll biblioteki, z której eksportowana jest funkcja. Ale natywne linkowanie c ++ wymaga pliku .lib, aby poprawnie "zobaczyć" implementacje w cpp, więc pomogło mi dodać plik .lib do konsolidatora -> wejście -> dodatkowe zależności.
[Zwykle zarządzany kod nie wykorzystuje eksportu i importu dll, używa odwołań, ale to była wyjątkowa sytuacja.]

whats_wrong_here
źródło