Опять undefined reference to
[Linker error] main.o:main.cpp:(.text+0x121): undefined reference to `имя функции члена'
для некоторых функций-членов (хотя в main.cpp вызываю все), причем сигнатура тех функций к которым нет претензий такая-же как у неопределенных линковщиком.
Если перенести текст из файла реализации в main.cpp, то компилируется нормально.
Вообще, такая проблема периодически возникает с другими проектами, но она решается переоткрытием среды (или подождать немного), но не в данном случае.
Менял приоритеты линкующихся файлов - результата не дало.
Проект состоит и из других моих h и cpp файлов, но они не влияют на результат.
Объясните мне, что происходит.
Код:
//test.h
class A {
private:
void Foo1(void);
public:
void Foo2(void);
void Foo3(void);
};
//test.cpp
#include "test.h"
inline void A::Foo1(void){
//code ...
}
inline void A::Foo2(void){
Foo1();
}
void A::Foo3(void){
Foo1();
}
//main.cpp
#include "test.h"
int main(int argc, char *argv[]){
A a;
a.Foo2();// [Linker error] ... undefined reference to `A::Foo2(void)'
a.Foo3();// Ok!
return 0;
}
class A {
private:
void Foo1(void);
public:
void Foo2(void);
void Foo3(void);
};
//test.cpp
#include "test.h"
inline void A::Foo1(void){
//code ...
}
inline void A::Foo2(void){
Foo1();
}
void A::Foo3(void){
Foo1();
}
//main.cpp
#include "test.h"
int main(int argc, char *argv[]){
A a;
a.Foo2();// [Linker error] ... undefined reference to `A::Foo2(void)'
a.Foo3();// Ok!
return 0;
}
Нужно смотреть команду линковки, которую формирует ваша среда разработки. От этого плясать.
Может быть среда косячит, а может и порядок при линковке важен...
А там дебугера нет разве? Не будучи осведомлённым в ваших IDE, могу сразу предположить, что объект не создан, и дело тут вовсе не в IDE. Курите свой текст лучше, ошибка происходит на стадии создания объекта.
А где в определниях расширение A:: ? Оно нужно.
Цитата: sadovoya
А где в определниях расширение A:: ? Оно нужно.
Да, спасибо, пропустил (код не копипастил). Исправлю.
Множественного включения заголовков нет?
В моем рабочем коде есть и там использую макро команды для невключения. Но в этом примере они, по-моему не требуются.
Тогда дичь какая-то. Что за компилятор?
Цитата: sadovoya
Тогда дичь какая-то. Что за компилятор?
MinGW 4.7.2 (шел вместе с Dev-Cpp). Но и в Borland то-же, только unresolved external.
Прикольно. У меня тоже MinGW, ничего подобного не наблюдалось. Еще и в билдере.. Даже на среду не похоже.
Цитата: sadovoya
Прикольно. У меня тоже MinGW, ничего подобного не наблюдалось. Еще и в билдере.. Даже на среду не похоже.
Сейчас проверил свой код (из этого поста), как и говорил ошибка есть.
А с путями все нормально, файлы в той-же папке, что main? Кстати иногда с русскими папками проблемы бывают.
Цитата: sadovoya
А с путями все нормально, файлы в той-же папке, что main?
Разумеется.
Вообще недавно прочитал, что inline функции могут быть встроены, когда объявляются в той же единице трансляции где используются. Так что если перенести текст из test.cpp в main.cpp то проблема исчезнет.
Единицей трансляции будет и так пара h и cpp по-моему. Еще в классах инлайнится либо, если определение сразу при объявлении в классе, либо с модификатором inline как у вас. Насчет единицы трансляции что-то сам уже засомневался.
Цитата: sadovoya
Единицей трансляции будет и так пара h и cpp по-моему. Еще в классах инлайнится либо, если определение сразу при объявлении в классе, либо с модификатором inline как у вас.
Да, но ведь Foo2 вызывается в main. А к Foo1, вообще претензий нет. Кроме того, управлять компиляцией inlain функций можно ключами компилятора, но у меня все по умолчанию.
Проблема действительно в inline. Порылся в сети, у многих проблема при описании в cpp. Еще узнал, что некотрые компиляторы умеют правильно находить их в cpp, но на это тратится время, и зависит от настроек. В основном рекомендуют описывать в хедере. Хуже вариант - описывать во всех единицх трансляции, которые их используют.
1. Создать файл с именем как заголовок, но с расширением ".inl" (так поступают большинство корпоративных разработчиков).
2. В этом файле разместить реализацию громоздких методов.
3. Для подсоединения созданного файла к заголовку в конце заголовочного файла указать директиву
#include "<Имя заголовка>.inl"
Лично я рекомендую эту директиву применять в завершении пространства имен (namespace).
Повторюсь - это не догма. "Инлайн" файл может иметь отличное от заголовка название и "цепляться" разными заголовками. Всё зависит от применения.
Следует также помнить, что "ругательство" inline, по своей сути, рудимент. Большинство компиляторов (современных) будет использовать этот принцип (inline) в том случае, если вы располагаете реализацию метода в заголовке. В некоторых компиляторах - это регулируется ключами.