Qt程序关于 undefined refrence to vtable for xxx的解决

来源:互联网 发布:印刷报价软件好用吗 编辑:程序博客网 时间:2024/06/06 04:57

今天在编译MITK的教程示例程序时遇到 Error: xxx.cpp.o中未定义的引用vtable for xxx,???虚函数表?还指出我的构造函数是虚函数??WTF,我的构造函数怎么会是虚函数。。。奇怪的是CMakeLists.txt中也写清楚add_executable()需要的源文件, 源文件绝对没有语法问题。

查阅了半天,发现是因为xxx.cpp的类继承自QObject, 却没有手动给xxx.cpp进行moc编译,所以只include "xxx.h"根本找不到对应的函数实现,这就涉及到了Qt的元对象系统。

Qt 元对象系统实现了对象之间通信机制——信号和槽,并提供了运行时类型信息和动态属性系统。元对象系统是 Qt 类库独有的功

能,是 Qt 对标准 C++ 的扩展。使用元对象系统的前提是需要三件事情:

  • ①直接或间接地以 QObject 为基类,这样才能利用元对象系统的功能,Qt 的窗体和控件最顶层的基类都是 QObject。
  • ②将 Q_OBJECT 放在类声明的私有段落,以启用元对象特性,如动态属性、信号和槽等。之前遇到的例子 Q_OBJECT 都是在类
声明里的第一行,没有加 private 字样,因为类声明默认就是私有的。
  • ③元对象编译器(Meta-Object Compiler,moc)为每个 QObject 的子类提供必要的代码以实现元对象特性。
moc 工具读取 C++ 源码,找到一个或多个包含 Q_OBJECT 宏的类声明,然后生成额外的代码文件,如 moc_widget.cpp ,里面包

含实现元对象系统的代码。生成的源码文件可以包含在类原有的源文件里,如在 widget.cpp 里包含:#include "moc_widget.cpp"
这种包含方式看起来比较别扭,Linux 上的开发工具 KDevelop 自动生成的代码是这么用的。第二种方式是编译链接时揉到一起,

QtCreator 生成的代码就是通过编译链接时,把 moc_widget.o 与其他目标文件链接到一起,这种方式不用改源代码,相对而言比较顺

眼。

除了提供信号和槽机制用于对象之间的通信(这是主要任务),元对象系统还提供了更多的特性:

  • QObject::metaObject() 函数返回当前类对象关联的元对象(meta-object)。
  • QMetaObject::className() 函数返回当前对象的类名称字符串,而不需要 C++ 编译器原生的运行时类型信息
(run-time type information,RTTI)支持。
  • QObject::inherits() 函数判断当前对象是否从某个基类派生,判断某个基类是否位于从 QObject 到对象当前类的继承树上。
  • QObject::tr() 和 QObject::trUtf8() 函数负责翻译国际化字符串,因为 Qt5 规定源文件字符编码是 UTF-8,所以这两个函数现在功
能是一样的。
  • QObject::setProperty() 和 QObject::property() 函数用于动态设置和获取属性,都通过属性名称字符串来 操作。
  • QMetaObject::newInstance() 构建一个当前类的新实例对象。
元对象系统还提供了 qobject_cast() 函数,可以对基于 QObject 的类对象进行转换,qobject_cast() 函数功能类似标准 C++ 的

dynamic_cast()。当然 qobject_cast() 的优势在于不需要编译器支持 RTTI,而且跨动态链接库之间的转换也是可行的。简单地说,

原本是派生类的对象指针,就可以转为基类对象指针来用(转换得到可用值),其他情况都会得到 NULL 指针。比如:
MyWidget 是 QWidget 的派生类,并且类声明带有 Q_OBJECT 宏,新建一个对象:
QObject *obj = new MyWidget;
虽然 obj 是一个 QObject *,但它本质是一个 MyWidget 对象指针,可以转成基类指针:
QWidget *widget = qobject_cast<QWidget *>(obj);

但是如果将 MyWidget 对象指针转成其他无关的类对象指针,就会失败:
 QLabel *label = qobject_cast<QLabel *>(obj);
label的数值就是 NULL。


说了那么多,言归正传, 命令行:

moc xxx.cpp -o moc_xxx.cpp

在CMakeLists.txt中添加add_executable( .. xxx.cpp moc_xxx.cpp ...) 采用编译链接的方法,顺利解决undefined reference to vtable for xxx问题。

阅读全文
0 0
原创粉丝点击