Программируя на Qt и время от времени проверяя форумы, приходится наблюдать, что программисты часто борятся с сообщениями вида «undefined reference to vtable».
Попробую описать ситуации, когда может возникнуть данная ошибка, и дать несколько советов, как избежать её.
Чаще всего данное сообщение всплывает, если вы используете MOC.
MOC (Meta-Object Compiler, переводится как Метаобъектная система/компилятор) – механизм, который расширяет синтаксис C++.
MOC:
- необходим для механизма сигналов-слотов;
- позволяет программисту получать метаинформацию о подклассах QObject (QObject::metaObject());
- используется для интернационализации приложений (QObject::tr());
- содержит в себе полезные расширения синтаксиса C++.
MOC компилятор находит и обрабатывает все заголовочные проекта.
При появлении ошибки «undefined reference to vtable», первым делом очистите проект и пересоберите его, не забыв запустить qmake:
make clean
# удалите вручную все moc-файлы, если они остались после выполнения make clean
rm Makefile
qmake
make
Если ошибка не исчезла, то проверьте файл проекта (*.pro). Проверьте, чтобы все необходимые заголовочные файлы (включающие сигналы и слоты особенно) были включены в проект. Список заголовочных файлов должен содержаться в переменной HEADERS:
HEADERS += firstHeaderFile.h
otherHeaderFile.h
secondHeaderFile.h
Если вы используете в проекте папку, содержащую заголовочные файлы, убедитесь, что добавили эту папку в переменную INCLUDEPATH:
INCLUDEPATH += ./include
Если обнаружили забытый h-, hpp-файл – пересоберите проект заново.
Проблема осталась? Тогда ещё варианты:
- Загляните в c-, cpp-файлы и убедитесь, что классы там не определяются. MOC разбирает только заголовочные файлы;
- Каждый класс, который имеет сигналы или слоты должен наследоваться от QObject, напрямую или нет.
В начале определения таких классов обязательно должнен стоять макрос Q_OBJECT, к примеру:class MyWidget : public QWidget
{
Q_OBJECT
/* класс наследуется от QWidget, а значит и от QObject,
* следовательно должен содержать макрос Q_OBJECT.
* Если класс наследуется от QObject, но не содержит сигналов или слотов,
* то не обязательно включать макрос в описание класса.
*/
...
} - Ещё одна вещь, которую можно проверить.
Удалите Makefile и посмотрите, что выдаст qmake в Makefile:
rm Makefile
qmake
Откройте Makefile редактором и найдите следующие строки:
и
compiler_moc_header_make_all:
compiler_moc_header_clean:
Например, в моем Makefile есть:mocclean: compiler_moc_header_clean compiler_moc_source_clean
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
compiler_moc_header_make_all:
release/moc_mainwindow.cpp release/moc_SystemConfiguration.cpp release/moc_InstrumentConfiguration.cpp release/moc_ModuleConfiguration.cpp release/moc_ChannelConfiguration.cpp
compiler_moc_header_clean:
-$(DEL_FILE) releasemoc_mainwindow.cpp releasemoc_SystemConfiguration.cpp releasemoc_InstrumentConfiguration.cpp releasemoc_ModuleConfiguration.cpp releasemoc_ChannelConfiguration.cpp
Каждый заголовочный файл, содержащийся в проекте и
нуждающийся в обработке MOC-компилятора, должен находиться в этих строках.
Имя файла будет начинаться с прифекса «moc_».
Проверьте, что в список включены все h-файлы (точнее, только те, которые требуют обработку MOC-компилятором).
Если Вы не обнаружили какой-либо moc-файл, не спешите править руками Makefile,
просто подправьте pro-файл нужным образом.
Если файл проекта правилен, то qmake генерирует правильный Makefile.
link
|
Автор | Тема: Если вылезает ошибка «undefined reference to vtable for …» [СОВЕТ] (Прочитано 55458 раз) |
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
?
Log in
If this type of authorization does not work for you, convert your account using the link
-
-
September 19 2013, 21:02
- IT
- Cancel
Тысячу и один раз это отвечено на stackoverflow, и в тысячу и один раз начинается тупак под вечер, когда не удается вспомнить все возможные причины. Итак, причины error: undefined reference to `vtable и пути их решения:
- Класс унаследовал чистые виртуальные функции и не переопределил их. Определите их.
- Класс был объявлен наследником QObject с макросом Q_OBJECT после moc-а. Сделайте moc заново.
- Заголовочный файл не включен в проект или был включен до появления в нём Q_OBJECT-а. Пересоберите проект, либо (короткий путь) обновите таймштамп файла проекта и сделайте Build.
Например, быстрый способ обновить таймштампы всех подпроектов:# find . -name '*.pro' -exec touch '{}' ;
- Макрос Q_OBJECT используется не в заголовочном файле. Нужно добавить
#include "<BASENAME>.moc"
в исходник, это укажет qmake-у выполнитьmoc
для этого файла, чтобы сгенерировать код для QObject-а (сигналы/слоты и т.д.). Поместить #include «<BASENAME>.moc» нужно просто в конце файла <BASENAME>.cpp и затем пересобрать проект.
За этот пункт спасибо ответу в вопросе http://stackoverflow.com/questions/21729769/why-is-vtable-linking-issue-while-adding-javascript-window-object.
И отдыхайте чаще. Во всех случаях.
14 Years Ago
I’m self studying from the book, C++ Primer Plus Fifth Edition, by Stephen Prata. The following relates to Chapter 13, Page 699, Programming Exercise #4. One task is to write the derived class method definitions based upon the given prototypes. The following are the said prototypes.
class Port
{
private:
char *brand;
char style[20]; // i.e. tawny, ruby, vintage
int bottles;
public:
Port(const char *br = "none", const char *st = "none", int b = 0);
Port(const Port &p); // copy constructor
virtual ~Port() { delete [] brand;}
Port & operator=(const Port &p);
Port & operator+=(int b);
Port & operator-=(int b);
int BottleCount() const {return bottles;}
virtual void Show() const;
friend ostream &operator<<(ostream &os, const Port &p);
};
class VintagePort : public Port
{
private:
char * nickname; // i.e. The Noble, or Old Velvet, etc.
int year; // vintage year
public:
VintagePort();
VintagePort(const char *br, int b, const char *nn, int y);
VintagePort(const VintagePort &vp);
~VintagePort() {delete [] nickname;}
void Show() const;
friend ostream & operator<<(ostream &os, const VintagePort & vp);
};
You will note that the base class destructor is virtual. That the derived class destructor is implemented inline.
I was creating the derived class method definitions in a cpp file and couldn’t get the project to progressively compile correctly. At my first method definition, a default constructor, the compiler kept spitting out this error message:
Chapter-13pe-13-04port.cpp|74|undefined reference to `vtable for VintagePort’
The line number was pointing to my derived class constructor definition. I did some googling around and came across this workaround. I removed the inline effect of the derived class destructor, made that into a method definition in the cpp file and presto, compilation succeeded.
Am I to assume that the example in the book, as regards the inline feature of a derived class destructor, is in error. Are there any other explanations.
Recommended Answers
> I was creating the derived class method definitions in a cpp file
> and couldn’t get the project to progressively compile correctly.
> At my first method definition, a default constructor,
> the compiler kept spitting out this error message:this is perhaps the most obscure error message …
Jump to Post
All 10 Replies
14 Years Ago
> I was creating the derived class method definitions in a cpp file
> and couldn’t get the project to progressively compile correctly.
> At my first method definition, a default constructor,
> the compiler kept spitting out this error message:
this is perhaps the most obscure error message that gcc (actually the linker) spits out, but the reason is simple:
the compiler has to put the (one and only one) vtable for a class into some object file or the other. it puts it into the object file for the translation unit where the definition of the first non-pure-virtual out-of-line virtual member function is present. if there is no such definition, you get this rather unhelpful linker error message.
you would be able to progressively compile the code even if a non-pure virtual function is not defined, but to be able to link without errors, every such function must have a definition (at least a stub). and to prevent the non-creation of a v-table by the compiler, at least one of the non-pure virtual functions will have to be defined out-of-line.
gcc has a faq about this: http://gcc.gnu.org/faq.html#vtables
> Am I to assume that the example in the book, as regards the inline feature
> of a derived class destructor, is in error.
i think it is not a particularly good book, but in this case neither the book nor the compiler is in error.
if you define the destructor inline, and void VintagePort::Show() const
out-of-line, the error will go away. there has to be at least one out-of-line definition of a non-pure-virtual function.
note: the microsoft compiler (as well as several other compilers) does not require this; it instantiates a v-table with internal linkage in *every* translation unit in which such a header (all non-pure virtual functions are inline) is included. this violates the c++ one definition rule for v-tables, but as always, folks at redmond tend to value pragmatism highly. and they do give you __declspec(novtable)
to suppress the proliferation of v-tables.
14 Years Ago
Thank you very much, this has certainly cleared things up. In a way, I’m glad I came across this problem, hopefully it won’t catch me out again, when progressively compiling.
14 Years Ago
Hi … I hope this helps someone out there….
I’m using netbeans with the C++ plugin in linux. I got the vtable error, and after a long time I figured out the solution..
basically the class I was trying to use was not added into the project. The class files (.cpp, .h) were in the project folder, and i was editing the files, etc… but they just wouldn’t compile because they weren’t added into the project.
so just right click the project, select «add existing items» and choose the file and add the files to the project… now it should compile, fingers crossed
13 Years Ago
I have also seen this with GCC 4 when a virtual destructor is missing a body
eg:
virtual ~MyClass(void);
should be:
virtual ~MyClass(void){};
13 Years Ago
I have also seen this with GCC 4 when a virtual destructor is missing a body
eg:
virtual ~MyClass(void);
should be:
virtual ~MyClass(void){};
Also if you declare a virtual constructor but forget the ‘~’ in its definition, e.g.:
virtual ~A(); // declaration in .h file
A::A() {} // .cpp implementation missing ~ in function name
13 Years Ago
Also if you declare a virtual constructor but forget the ‘~’ in its definition, e.g.:
virtual ~A(); // declaration in .h file
A::A() {} // .cpp implementation missing ~ in function name
That doesn’t make sense… Removing ‘~’ makes your function a ‘Constructor’ instead of a ‘Destructor’…
The only difference between the .H version and the .CXX version is that you don’t put ‘virtual’ in the .CXX file…
12 Years Ago
I’m self studying from the book, C++ Primer Plus Fifth Edition, by Stephen Prata. The following relates to Chapter 13, Page 699, Programming Exercise #4. One task is to write the derived class method definitions based upon the given prototypes. The following are the said prototypes.
class Port { private: char *brand; char style[20]; // i.e. tawny, ruby, vintage int bottles; public: Port(const char *br = "none", const char *st = "none", int b = 0); Port(const Port &p); // copy constructor virtual ~Port() { delete [] brand;} Port & operator=(const Port &p); Port & operator+=(int b); Port & operator-=(int b); int BottleCount() const {return bottles;} virtual void Show() const; friend ostream &operator<<(ostream &os, const Port &p); }; class VintagePort : public Port { private: char * nickname; // i.e. The Noble, or Old Velvet, etc. int year; // vintage year public: VintagePort(); VintagePort(const char *br, int b, const char *nn, int y); VintagePort(const VintagePort &vp); ~VintagePort() {delete [] nickname;} void Show() const; friend ostream & operator<<(ostream &os, const VintagePort & vp); };
You will note that the base class destructor is virtual. That the derived class destructor is implemented inline.
I was creating the derived class method definitions in a cpp file and couldn’t get the project to progressively compile correctly. At my first method definition, a default constructor, the compiler kept spitting out this error message:
The line number was pointing to my derived class constructor definition. I did some googling around and came across this workaround. I removed the inline effect of the derived class destructor, made that into a method definition in the cpp file and presto, compilation succeeded.
Am I to assume that the example in the book, as regards the inline feature of a derived class destructor, is in error. Are there any other explanations.
This error also arises in gcc if a class is inherited from a class in non included library but added include file.
12 Years Ago
Thanks. Procrastes’s answer helped. Virtual destructor was missing a body and the error was gone when I fixed it.
12 Years Ago
Dont put virtual if you dont need.
12 Years Ago
Had the same problem.
Solved by removing the macro definition for LIB_HAS_DLL.
When building an application for cross-compiling, people usually include a MACRO BLOCK similar to the one show below and use function linkage such as
LIB_FUN void myfunc();
by defining LIB_HAS_DLL this becomes __declspec(dllimport) void myfunc();
adding LIB_BUILD_DLL it becomes __declspec(dllexport) void myfunc();
removing -DLIB_HAS_DLL from the cmdline causes the function to be auto-import and mingw resolves the vtable.
/* DEFINITION for DLL Linkage */
#ifdef LIB_HAS_DLL
# ifdef LIB_BUILD_DLL
# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
# define LIB_FUN __declspec(dllexport)
# else
# define LIB_FUN
# endif
# else
# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
# define LIB_FUN __declspec(dllimport)
# else
# define LIB_FUN
# endif
# endif
#else
# define LIB_FUN
#endif
Reply to this topic
Be a part of the DaniWeb community
We’re a friendly, industry-focused community of developers, IT pros, digital marketers,
and technology enthusiasts meeting, networking, learning, and sharing knowledge.
This topic has been deleted. Only users with topic management privileges can see it.
i have created a base class called Base which inherits from QDialog:
@
class Base : public QDialog
{
Q_OBJECT
public:
Base ();
—
};
@
And added this file to PATH: /usr/local/include/ and its source file to /usr/local/src/
Now I am using this as a base class in my application:
@
class Test:public Base
{
Q_OBJECT
—
};
@
The application is giving error:
undefined reference to ‘vtable for A’.
Does anyone know why i am getting this error??
P.S. :—Here the Base class is not an abstract class.
[edit, code tags added, koahnig]
Please check out the forum rules for «code wrappings.»:http://qt-project.org/wiki/ForumHelp#e3f82045ad0f480d3fb9e0ac2d58fb01 This time I have added them for you.
This is a very general error message typically coming up when a class is not properly initialized yet. You need to check out the initialization of members in your class respectively if the sequence of their initialization is correct when doing a recursive initialization. For the last case you should have received a warning as long as the sequence is not correct within the class.
One possible (and unfortunately common with Qt and qmake) cause is that qmake did not pick up the Q_OBJECT macro in your class declaration yet. If that is the case, then the Q_OBJECT macro is declaring some methods that are not implemented by moc yet.
Did you re-run qmake on your project before trying to rebuild?
Yes…i tried that….but it is giving the same error on building d project.
So, show the actual error please. My crystal ball is at the repair shop…
Do you have virtual methods?
Are the above definitions in an include file or a .cpp file ?
There is no virtual method, right now.
I am just testing how this concept works.
And these definitions are include file.
base.h file
@#ifndef BASE_H
#define BASE_H
#include <QDialog>
class Base : public QDialog
{
Q_OBJECT
public:
protected:
explicit Base(QWidget *parent = 0, Qt::WindowFlags f = 0);
signals:
public slots:
};
#endif // BASE_H@
base.cpp file
@#include «base.h»
Base::Base(QWidget *parent, Qt::WindowFlags f):
QDialog(parent, f)
{
}@
Added base.h in PATH: /usr/local/include/ and base.cpp in PATH:/usr/local/src/.., since i dont want to add this base class in my application explicitely.
TestBase project:
This is the class inherits Base class:
test.h file
@#ifndef TEST_H
#define TEST_H
#include «base.h»
class Test : public Base
{
Q_OBJECT
public:
explicit Test(QWidget *parent = 0);
~Test();
private:
};
#endif // TEST_H
@
test.cpp file»:
@#include «test.h»
Test::Test(QWidget *parent) :
Base(parent, Qt::FramelessWindowHint ),
{
}
Test::~Test()
{
}
@
main.cpp:
@#include <QtGui/QApplication>
#include «dialog.h»
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
@
Errors after make command:
test.o: In function Test::~Test()': test.cpp:(.text+0x1f): undefined reference to
vtable for Base’
test.cpp:(.text+0x27): undefined reference to vtable for Base' test.o: In function
Test::Test(QWidget*)’:
test.cpp:(.text+0x96): undefined reference to Base::Base(QWidget*, QFlags<Qt::WindowType>)' test.cpp:(.text+0xee): undefined reference to
vtable for Base’
test.cpp:(.text+0xf6): undefined reference to vtable for Base' moc_test.o: In function
Test::qt_metacall(QMetaObject::Call, int, void**)’:
moc_test.cpp:(.text+0x31): undefined reference to Base::qt_metacall(QMetaObject::Call, int, void**)' moc_test.o: In function
Test::qt_metacast(char const*)’:
moc_test.cpp:(.text+0x77): undefined reference to Base::qt_metacast(char const*)' moc_test.o:(.rodata+0x20): undefined reference to
Base::staticMetaObject’
moc_test.o:(.rodata._ZTI4Test[typeinfo for Test]+0x10): undefined reference to `typeinfo for Base’
collect2: ld returned 1 exit status
make: *** [testMMIBase] Error 1
[quote author=»Kritika» date=»1391494986″]Added base.h in PATH: /usr/local/include/ and base.cpp in PATH:/usr/local/src/.., since i dont want to add this base class in my application explicitely.
[/quote]
That is interesting. What do you mean by that? Do you mean that you’re not actually compiling in base.h and base.cpp into your application? If so: that won’t work. If you don’t want Base in your main application, you’ll need to put it in a library that you link against. Otherwise, how is your application to know at run time what base actually is?
If you don’t include base.h and base.cpp in your project directory, then they will not be compiled.
You have two options:
Put base.h and base.cpp in your project directory.
Compile base.h and base.cpp into an an external library. Then, link that library to your project.
@JKSH- Thanks….
Like u said, i compiled this base class, this created four versioned libraries:
libbase.so
libbase.so.1
libbase.so.1.0
libbase.so.1.0.0
and then, i linked the TestBase project against it. The application did build successfully, but giving another error on run:
«error while loading shared libraries: libbase.so.1: cannot open shared object file: no such file or directory»
Can anybody explain why i am getting this error..
The shared library can’t be found. So, you’ll need to deploy it to a location where it can be found.
The problem is fixed..
Now, i am adding library in the application by the option Add Library on right click. This is linking library as well as including header file. And this is working well…Although i still couldnt figure out why previous thing was not working.
[quote author=»Kritika» date=»1391529236″]The problem is fixed..[/quote]Great!
[quote]Although i still couldnt figure out why previous thing was not working.[/quote]Because you didn’t tell your program where to find the library previously.