Ошибка "undefined reference/unresolved external symbol" в C++: причины и исправление
Что такое undefined reference / unresolved external symbol?
Эта ошибка возникает на этапе компоновки (линковки), когда компилятор уже успешно обработал все исходные файлы, но линковщик (linker) не может найти реализацию (тело) функции или переменной, которая была объявлена (например, в заголовочном файле) или использована. В вашем случае: в main.cpp вызывается MyClass::myFunction(), но линковщик не видит её определения из myclass.cpp.
Почему это происходит в вашем коде?
Вы компилируете только main.cpp: g++ main.cpp -o program. Файл myclass.cpp не участвует в компиляции. Компилятор обрабатывает main.cpp, видит объявление класса в myclass.h и генерирует вызов myFunction, но не знает, где её код. Линковщик затем ищет этот код во всех объектных файлах, но находит только main.o — и выдаёт ошибку.
Как это исправить?
Нужно скомпилировать и связать оба файла вместе. Есть несколько способов:
1. Компиляция всех .cpp файлов в одной команде
g++ main.cpp myclass.cpp -o program
Или для Visual Studio (из командной строки разработчика):
cl main.cpp myclass.cpp
2. Раздельная компиляция (рекомендуется для больших проектов)
g++ -c main.cpp -o main.o
g++ -c myclass.cpp -o myclass.o
g++ main.o myclass.o -o program
Флаг -c означает «только компиляция, без линковки». Затем вы линкуете объектные файлы.
3. Использование make-файла или CMake
Для автоматизации процесса создайте Makefile:
program: main.o myclass.o
g++ main.o myclass.o -o program
main.o: main.cpp myclass.h
g++ -c main.cpp -o main.o
myclass.o: myclass.cpp myclass.h
g++ -c myclass.cpp -o myclass.o
Или используйте CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_executable(program main.cpp myclass.cpp)
Другие частые причины undefined reference:
- Забыли #include заголовочный файл — но не ваш случай.
- Не подключили библиотеку (например,
-lmдля математических функций,-lpthreadдля потоков). - Опечатка в имени функции в объявлении или определении (например,
myfunctionvsmyFunction). - Определение функции в .cpp, но не объявлено в .h — линковщик не найдёт, если вызывать из другого файла.
- Статические или inline функции — если функция объявлена как
staticв заголовочном файле, она не будет видна в других единицах трансляции. - Функции-члены класса, объявленные, но не определённые — проверьте, что все методы имеют реализацию.
Как отлаживать?
Используйте флаги для линковщика: g++ -v main.cpp myclass.cpp -o program покажет, какие файлы ищутся. В Visual Studio включите подробный вывод линковки (Project Properties → Linker → General → Show Progress).
Ваш код корректен, проблема только в том, что вы не передали myclass.cpp компилятору. Добавьте его в команду — и всё заработает!
Альтернативный подход: проверьте настройки IDE и порядок компиляции
Если вы используете IDE (Visual Studio, Code::Blocks, CLion), ошибка может возникать, если файл myclass.cpp не добавлен в проект. В Visual Studio: щёлкните правой кнопкой по проекту → Add → Existing Item → выберите myclass.cpp. В Code::Blocks: в панели проектов добавьте файл через Add files.
Также проверьте порядок файлов при линковке. В некоторых старых компиляторах (например, MinGW) порядок имеет значение: библиотеки должны идти после объектных файлов, которые их используют. Для вашего случая команда g++ main.cpp myclass.cpp всегда корректна, но если вы добавляете библиотеки, ставьте их в конец:
g++ main.o myclass.o -lpthread -o program
Дополнительная причина: забыли extern "C"
Если вы смешиваете C и C++ код, функция, объявленная в C-стиле, должна быть обёрнута в extern "C":
// myclass.h
#ifdef __cplusplus
extern "C" {
#endif
void c_function();
#ifdef __cplusplus
}
#endif
Иначе линковщик будет искать искажённое (mangled) имя C++, а найдёт C-имя — и выдаст unresolved external.
В вашем случае это не актуально, но полезно знать для будущих проектов.