Нерозв’язаний зовнішній символ у файлах об'єктів


180

Під час кодування у Visual Studio у мене з’явилася невирішена помилка зовнішнього символу, і я не маю уявлення, що робити. Я не знаю, що не так. Не могли б ви розшифрувати мене? Де я повинен шукати, які помилки?

1>Form.obj : error LNK2019: unresolved external symbol "public: class Field * __thiscall Field::addField(class Field *)" (?addField@Field@@QAEPAV1@PAV1@@Z) referenced in function "public: void __thiscall Form::parse(class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?parse@Form@@QAEXAAV?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>Form.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall Field::parse(class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?parse@Field@@UAEXAAV?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: __thiscall InputField::InputField(class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > &)" (??0InputField@@QAE@AAV?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>Form.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Field::prompt(void)" (?prompt@Field@@UAEXXZ)
1>Form.obj : error LNK2001: unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Field::getName(void)" (?getName@Field@@UAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
1>Form.obj : error LNK2001: unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Field::getType(void)" (?getType@Field@@UAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
1>Form.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Field::describe(void)" (?describe@Field@@UAEXXZ)
1>C:\Users\tomy\Documents\Visual Studio 2010\Projects\zapoctovkac++\Debug\zapoctovkac++.exe : fatal error LNK1120: 6 unresolved externals

26
Невирішений символ - це той, який ви десь декларували, але ніколи не визначали. Зазвичай це означає, що ви # включили якийсь файл заголовка бібліотеки сторонніх розробників, але не повідомили посилання, де знайти відповідні файли .obj для бібліотеки.
deong

7
Досить поширеною помилкою є те, що ви визначаєте функцію як окрему і забуваєте селектор класів у вашому файлі .cpp : Ви робите це (неправильно): void myFunc() { /* do stuff */ } Замість цього (праворуч): void A::myFunc() { /* do stuff */ }
jave.web

Ви також можете додати дужки безпосередньо в заголовку файлу , якщо ви не хочете , щоб визначити його більше в файлі .cpp, як це: void myFunc() {};.
Patapoom

Відповіді:


303

Ця помилка часто означає, що деяка функція має декларацію, але не визначення.

Приклад:

// A.hpp
class A
{
public:
  void myFunc(); // Function declaration
};

// A.cpp

// Function definition
void A::myFunc()
{
  // do stuff
}

У вашому випадку визначення неможливо знайти. Проблема може полягати в тому, що ви включаєте файл заголовка, який містить деякі декларації функції, але ви:

  1. не визначайте функції у вашому файлі cpp (якщо ви написали цей код самостійно)
  2. не включають файл lib / dll, який містить визначення

Поширена помилка полягає в тому, що ви визначаєте функцію як окрему і забуваєте селектор класів, наприклад A::, у своєму .cpp- файлі:

Неправильно: void myFunc() { /* do stuff */ }
правильно: void A::myFunc() { /* do stuff */ }


2
Як включити згаданий файл lib до мого проекту?
tmj

@tMJ Це залежить від того, яке середовище ви використовуєте. Я б шукав підручники в Інтернеті чи на цьому сайті.
Кріс Морріс

@ChrisMorris Визначення функції було недоступне не тому, що я не пов’язав це належним чином чи щось. Але, оскільки dll не був у пам'яті і його потрібно було завантажити через виклик LoadLibrary. (FTR)
tmj

2
Остання порада була саме тут проблемою. Я робив void myFunc() {}замість цього A::void myFunc() {}.
Чарльз

Блискуча відповідь. Я фактично забув і те, і інше (1), а потім частину A :: після копіювання методу в інше місце.
RoG

24

Перевірте, чи включаєте ви всі вихідні файли у своє рішення, на яке ви посилаєтесь.

Якщо ви не включаєте Fieldв свій проект вихідний файл (і, таким чином, реалізацію) для класу, він не буде побудований, і ви не зможете зв’язатись під час компіляції.

Або, можливо, ви використовуєте статичну або динамічну бібліотеку і забули розповісти лінкеру про .libs?


3
Посилання на правильні файли lib вирішило проблему. Використовуйте Project-> Properties-> Linker-> General-> Additional Directories Directories and Project-> Properties-> Linker-> Input-> Additional Dependpendents для позначення каталогу lib та файлів lib
zak

11

Схоже, що у бібліотеці відсутня або включена, ви можете спробувати розібратися, який клас вашої бібліотеки має getName, getType тощо ... і помістити це у файл заголовка чи за допомогою #include.

Крім того, якщо вони трапляються із зовнішньої бібліотеки, обов’язково посилайтеся на них у файлі проекту. Наприклад, якщо цей клас належить abc.lib, то у вашій Visual Studio

  1. Клацніть на Властивості проекту.
  2. Перейдіть у Властивості конфігурації, C / C ++, Генеруйте, переконайтесь, що ви вказуєте місце abc.lib у розділі Додаткові включення каталогів. У розділі Linker, Input переконайтеся, що ви маєте abc.lib у розділі Додаткові залежності.

9

Я щойно бачив проблему, я не можу викликати функцію з головного у .cpp-файлі, правильно оголошеному у .h-файлі та визначеному у .c-файлі. Зустрічається помилка лінкера. Тим часом я можу викликати функцію із звичайного .c-файлу. Можливо, це залежить від режиму виклику. Рішенням було додати наступні рядки препрокору у кожен .h файл:

#ifdef __cplusplus
extern "C"
{
#endif

і це врешті-решт

#ifdef __cplusplus
}
#endif

7

У мене виникла помилка, коли мій проект був складений як проект x64 . і я використав бібліотеку, яка була складена як x86 .

Я перекомпілював бібліотеку як x64 і це вирішило.


5

іноді, якщо доданий новий файл заголовка, і ця помилка починає виникати через це, вам потрібно додати бібліотеку, щоб позбутися unresolved external symbol.

наприклад:

#include WtsApi32.h

знадобиться:

#pragma comment(lib, "Wtsapi32.lib") 

4

У мене були ті ж помилки посилань, але з тестового проекту, який посилався на інший dll. З'ясувалося, що після додавання _declspec(dllexport)перед кожною функцією, яка вказана у повідомленні про помилку, посилання працювало добре.


3

Я вважаю, що більшість пунктів щодо причин та засобів усунення були охоплені всіма учасниками цієї теми. Я просто хочу вказати на свою "невирішену зовнішню" проблему, вона була викликана типом даних, визначеним як макрос, який замінюється інакше, ніж очікувалося, в результаті чого цей неправильний тип надходить до відповідної функції, а оскільки функція з типом ніколи не визначається, її неможливо було вирішити. Зокрема, під C / C ++ -> мовою є атрибут під назвою "Treat WChar_t As Built in Type", який мав би бути визначений як "Ні (/ Zc: wchar_t-)", але в моєму випадку це не було.


дякую, це спричиняє проблему з моєї настройки ("Ні (/ Zc: wchar_t-)")
Нойпі Гілас

2

На додаток до чудової відповіді Кріса Морріса вище, я знайшов дуже цікавий спосіб, коли ви можете отримати цю саму помилку, якщо ви звертаєтесь до віртуального методу, який не встановлений на чистому рівні, але не має власної реалізації. Це саме та сама причина (компілятор не може знайти реалізацію методу, а отже, шахрайства), але мій IDE не помилився цієї помилкою.

наприклад, наступний код отримає помилку компіляції з тим же повідомленням про помилку:

//code testing an interface
class test
{
   void myFunc(); 
}

//define an interface
class IamInterface
{
    virtual void myFunc();
}

//implementation of the interface
class IamConcreteImpl
{
    void myFunc()
    {
       1+1=2;
    }
}

Однак, змінивши IamInterface myFunc () на чистий віртуальний метод (метод, який "необхідно" реалізувати, що, ніж віртуальний метод, який є методом, "можна" перекрити) усуне помилку компіляції.

//define an interface
class IamInterface
{
    virtual void myFunc() = 0;
}

Сподіваємось, це допоможе наступній людині StackOverFlow перейти через код!



2

Обов’язково прикрасьте файли заголовків

#ifndef YOUR_HEADER_H
#define YOUR_HEADER_H

// your header code here

#endif

Погані речі - включаючи це - можуть трапитися, якщо цього не зробити


8
Як щодо використання #pragma once?
Аллен Лінаток

2

Ще одна можлива проблема (про яку я просто почесав голову протягом певного часу):

Якщо ви визначаєте свої функції як inline, вони, звичайно, мають бути визначені в заголовку (або вбудованому файлі), а не cpp .
У моєму випадку вони знаходились у вбудованому файлі, але лише тому, що вони були платформою для конкретної реалізації, і cpp включав цей відповідний вхідний файл… замість заголовка. Так, трапляється ** t.

Я думав, що я також залишу це тут, можливо, хтось інший зіткнеться з тим самим питанням і знайде його тут.


1
Кому хто це сприйняв: Залиште принаймні коментар, чому ви вважаєте, що відповідь неправильна чи не корисна. Потік без коментарів у кращому разі не вартий.
Йоганн Студанський

1

Мені просто важко було з цим. Все було логічно налаштовано. Я оголосив конструктора, але не визначив його

class SomeClass
{
   SomeClass();  // needs the SomeClass::SomeClass(){} function defined somewhere, even here
}

Я майже стукнув головою про клавіатуру, коли забув щось таке елементарне.


1

Я роблю деякі C ++ вперше за довгий час, і я отримую цю помилку, коли забуваю додати префікс ClassName :: для визначення функції, оскільки це трохи унікально для C ++. Тож не забудьте перевірити і на це!


1

Однією з можливих причин помилки цього лінкера можуть бути також inlineфункції, які оголошуються, але не визначаються у файлі заголовка, який потім включається десь ще. Вбудовані функції повинні бути визначені в кожній одиниці перекладу, в якій вони використовуються.


0

Вказівники

У мене була ця проблема і вирішено її за допомогою покажчика. Я бачу, що це не було вашим питанням, але я думав, що це згадаю, бо хотів би, щоб це було тут, коли я бачив це годину тому. Моя проблема полягала в оголошенні статичної змінної члена, не визначаючи її (визначення, яке потрібно прийти після деяких інших налаштувань), і, звичайно, вказівник не потребує визначення. Не менш елементарна помилка: P


3
Приклад був би дуже корисним тут.
moffeltje

0

У моїй проблемі був короткий сценарій, у ньому не було cppвизначено файлу. Це може бути дуже заплутано, оскільки Visual Studio має cppфайл у проекті, але щось інше повністю будується.


0

Моє питання полягало в тому, що: я повинен був зробити попереднє оголошення класу, ctor якого був "зовнішнім невирішеним".

У файлі, де я отримав помилку, я повинен був поставити щось подібне:

#include "ClassB" 

class ClassB; // this solved the problem

class ClassA{
    void foo(){
        ClassB* tmp = new ClassB();
        // ...
    }
};

Звичайно, мій проект набагато складніший, і це лише приклад фрагмента. Також, використовуючи простори імен, оголошуйте їх також .


0

Щойно витратив пару годин, щоб з'ясувати, що проблема в моєму головному файлі .cзамість.cpp

:/


0

Ще одна можливість перевірити, це була моя проблема цього разу.

Я додав функцію до бібліотеки і включив вихідну папку бібліотеки в шлях пошуку.

Але у мене також була папка зі старшою версією бібліотеки, переліченою раніше, тому VS використовував стару бібліотеку, і, звичайно, не знаходив нової функції.


0

Переконайтеся, що ви не намагаєтеся перевантажувати оператори вставки або вилучення як вбудовані функції. У мене була ця проблема, і вона пішла лише тоді, коли я видалив це ключове слово.


0

Що це спричинило у моєму випадку:

У мене був величезний файл Foo.cppбез Foo.h. Foo.cppпочалося так:

// ... 100 LOC here ...
namespace NS {
// ... 100 more LOC here ...
static int var;

Я видалив "статичне" ключове слово та додав Foo.hдо цього:

extern int var;

Ви бачите помилку?

Я повністю пропустив, що var спочатку був визначений у просторі імен, оскільки декларація простору імен була закопана в інший код. Виправлення полягає в тому, щоб змінити зовнішній вигляд так:

namespace NS {
     extern int var;
}

0

Можливою причиною помилки "Нерозв’язаний зовнішній символ" може бути функція, що викликає конвенцію.

Переконайтесь, що всі вихідні файли використовують однаковий стандарт (.c або .cpp) або вкажіть умову виклику.

В іншому випадку, якщо один файл - це файл C (source.c), а інший - файл .cpp, і вони посилаються на один і той же заголовок, тоді буде викинута помилка "невирішений зовнішній символ", оскільки функція спочатку визначається як функція C cdecl, але тоді файл C ++, використовуючи той самий заголовок, шукатиме функцію C ++.

Щоб уникнути "Невирішеної помилки зовнішнього символу", переконайтесь, що умова виклику функції зберігається однаковою для файлів, які її використовують.


0

Я прийшов сюди, шукаючи можливе пояснення, перш ніж детальніше ознайомитися з рядками, що передують помилці лінкера. Виявилося, це був додатковий виконуваний файл, для якого відсутня глобальна декларація!


0

Я тільки мав ту ж помилку , і мені вдається уникнути шляхом заміни ;з {}в файлі заголовка.

#ifndef XYZ_h
#define XYZ_h
class XYZ
{
    public:
    void xyzMethod(){}
}
#endif

Коли це void xyzMethod();не хотілося збирати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.