Неразрешенный внешний символ для статических членов класса


129

Проще говоря:

У меня есть класс, который состоит в основном из статических общедоступных членов, поэтому я могу сгруппировать вместе похожие функции, которые по-прежнему необходимо вызывать из других классов / функций.

В любом случае, я определил две статические переменные типа unsigned char в своей публичной области видимости класса, когда я пытаюсь изменить эти значения в конструкторе того же класса, я получаю ошибку «неразрешенный внешний символ» при компиляции.

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

    ...

    test();
};

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

Я новичок в C ++, так что не беспокойтесь. Почему я не могу этого сделать?

Ответы:


145

Вы забыли добавить определения, соответствующие вашим объявлениям X и Y

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

где-то. Вы также можете инициализировать статический член

unsigned char test::X = 4;

и снова вы делаете это в определении (обычно в файле CXX), а не в объявлении (которое часто находится в файле .H)


4
Если вы пишете библиотеку только для заголовков, вы можете использовать этот метод, чтобы избежать файла cpp: stackoverflow.com/questions/11709859/…
Шитал Шах

62

Объявления статических элементов данных в объявлении класса не являются их определением. Чтобы определить их, вы должны сделать это в .CPPфайле, чтобы избежать дублирования символов.

Единственные данные, которые вы можете объявлять и определять, - это интегральные статические константы. (Значения enumsмогут также использоваться как постоянные значения)

Возможно, вы захотите переписать свой код как:

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

test::test() {
}

Если вы хотите иметь возможность изменять свои статические переменные (другими словами, когда неуместно объявлять их как const), вы можете разделить свой код между .Hи .CPPследующим образом:

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

почему здесь, в .CPP, это "unsigned char test :: X = 1;" вместо "test :: X = 1;"? статическая переменная X уже определена, зачем еще нужен "unsigned char"? @sergtk
Пенни

@Penny Потому что "test :: X = 1;" интерпретируется как задание, тогда как то, что мы пытаемся сделать, - это определение.
Anonymous1847

4

Поскольку это первый поток SO, который, казалось, возник у меня при поиске «неразрешенных внешних элементов со статическими константными членами» в целом, я оставлю здесь еще одну подсказку для решения одной проблемы с неразрешенными внешними элементами:

Что касается меня, то я забыл отметить определение моего класса __declspec(dllexport), и при вызове из другого класса (за пределами границ этого класса) я, конечно, получил мою неразрешенную внешнюю ошибку.
Тем не менее, легко забыть, когда вы меняете внутренний вспомогательный класс на класс, доступный из другого места, поэтому, если вы работаете в динамически связанном проекте, вы также можете проверить это.


2

в моем случае я объявил одну статическую переменную в файле .h, например

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

и в myClass.cpp я попытался использовать эту m_nMyVar. Получена ошибка LINK, например:

ошибка LNK2001: неразрешенный внешний символ "public: static class ... Файл cpp, связанный с ошибкой ссылки, выглядит так:

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

Поэтому я добавляю код ниже поверх 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
}

тогда LNK2001 исчезнет.


0

В моем случае я использовал неправильную привязку.
Это управлялось c ++ (cli), но с собственным экспортом. Я добавил в компоновщик -> ввод -> ресурс ссылки сборки dll библиотеки, из которой экспортируется функция. Но для встроенного связывания c ++ требуется файл .lib, чтобы правильно «видеть» реализации в cpp, поэтому мне помогло добавить файл .lib в компоновщик -> ввод -> дополнительные зависимости.
[Обычно управляемый код не использует экспорт и импорт dll, он использует ссылки, но это была уникальная ситуация.]

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.