• error: undefined reference to ‘vtable for …’


    error: undefined reference to ‘vtable for …’

    这个报警就是子类没有实现父类的纯虚函数,奇怪的是自定义的虚函数都已经进行了定义,这个时候需要留意还有一种情况就是Qt中一个类继承了QObject,而且添加了Q_OBJECT宏,此时就可能出现上面的异常。

    原理

    测试源码

    object.h:
    #ifndef OBJECT_H
    #define OBJECT_H
    #include 
    class Object : public QObject
    {
        Q_OBJECT                        // 增加删除这个宏然后再编译
    public:
        explicit Object(QObject *parent = 0);
    };
    #endif // OBJECT_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    object.cpp:
    #include "object.h"
    Object::Object(QObject *parent) :
        QObject(parent)
    {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    main.cpp:
    #include 
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        return a.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Makefile

    在Object类中分别添加和删除Q_OBJECT宏,查看对应的两份Makefile:

    不包含Q_OBJECT

    当一个类中不包含Q_OBJECT,生成的makefile是这样的(精简):

    OBJECTS = main.o \
    		  object.o
    TARGET        = test2
    first: all
    all: Makefile $(TARGET)
    
    $(TARGET):  $(OBJECTS)  
    	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
    
    Makefile: test2.pro
    	$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ -o Makefile test2.pro
    
    main.o: main.cpp 
    	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
    
    object.o: object.cpp object.h
    	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o object.o object.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    重新编译的操作:

    15:35:55: 为项目test2执行构建步骤 …
    15:35:55: 正在启动 “/usr/bin/make” clean -w
    {1"?} {2?}
    make: Entering directory /home/u/delete/test2/test2' rm -f main.o object.o rm -f *~ core *.core make: Leaving directory /home/u/delete/test2/test2’
    15:35:55: 进程"/usr/bin/make"正常退出。
    15:35:55: 配置没有改变, 跳过 qmake 步骤.
    15:35:55: 正在启动 “/usr/bin/make” -w
    {1"?} {2?}
    make: Entering directory /home/u/delete/test2/test2' g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. -o main.o main.cpp g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. -o object.o object.cpp g++ -Wl,-O1 -o test2 main.o object.o -L/usr/lib/i386-linux-gnu -lQtCore -lpthread make: Leaving directory /home/u/delete/test2/test2’
    15:35:55: 进程"/usr/bin/make"正常退出。

    包含Q_OBJECT

    当一个类中包含Q_OBJECT的时候,对应的makefile是这样的(精简):

    OBJECTS = main.o \
    		  object.o \
    		  moc_object.o
    TARGET        = test2
    first: all
    
    all: Makefile $(TARGET)
    
    $(TARGET):  $(OBJECTS)  
    	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
    
    Makefile: test2.pro
    	$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ -o Makefile test2.pro
    
    moc_object.cpp: object.h
    	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) object.h -o moc_object.cpp
    
    main.o: main.cpp 
    	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
    
    object.o: object.cpp object.h
    	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o object.o object.cpp
    
    moc_object.o: moc_object.cpp 
    	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_object.o moc_object.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    然后有意思的就来了,重新编译的操作如下:

    15:34:24: 为项目test2执行构建步骤 …
    15:34:24: 正在启动 “/usr/bin/make” clean -w
    {1"?} {2?}
    make: Entering directory /home/u/delete/test2/test2' rm -f moc_object.cpp rm -f main.o object.o moc_object.o rm -f *~ core *.core make: Leaving directory /home/u/delete/test2/test2’
    15:34:24: 进程"/usr/bin/make"正常退出。
    15:34:24: 配置没有改变, 跳过 qmake 步骤.
    15:34:24: 正在启动 “/usr/bin/make” -w
    {1"?} {2?}
    make: Entering directory /home/u/delete/test2/test2' g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. -o main.o main.cpp g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. -o object.o object.cpp /usr/bin/moc-qt4 -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. object.h -o moc_object.cpp g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4 -I. -o moc_object.o moc_object.cpp g++ -Wl,-O1 -o test2 main.o object.o moc_object.o -L/usr/lib/i386-linux-gnu -lQtCore -lpthread make: Leaving directory /home/u/delete/test2/test2’
    15:34:25: 进程"/usr/bin/make"正常退出。

    两者区别

    从两种重新编译的具体执行过程来看,重新编译精简理解就是:

    make clean
    make
    
    • 1
    • 2

    当一开始编译一份不含Q_OBJECT宏的类时,他会生成一份Makefile,这份Makefile是基于没有Q_OBJECT宏qmake创建出来的,以本章例子为例,创建出来的Makefile并没有依赖moc_object.cpp,也没有创建该源文件的依赖生成关系;而该源文件就是Q_OBJECT宏对应的接口实现,因此,当仅修改头文件、在一个类中添加Q_OBJECT宏,此时即使是重新编译,由于.pro文件并没有变更,因此Makefile也没有变化,还是基于原先的逻辑进行编译,导致缺少对应的函数实现,进而导致编译器报警缺少函数实现的错误。

    解决

    处理方法就是重新qmake一下,也可以修改pro文件进而引发重新生成Makefile。

  • 相关阅读:
    DIY私人图床:使用CFimagehost源码自建无需数据库支持的PHP图片托管服务
    vnodeToString函数把vnode转为string(innerhtml)
    Snort中pcre和正则表达式的使用
    Redis内存淘汰策略
    2022年深信服杯四川省大学生信息安全技术大赛-CTF-Reverse复现(部分)
    高通Quick Charge快速充电原理分析
    Hadoop HBase Hive day3-day4.md
    oracle数据库增加表空间数据文件
    【linux】普通用户创建删除口令管理等用户管理
    Dart:补充
  • 原文地址:https://blog.csdn.net/lswdcyy/article/details/127588156