即使已实现虚拟方法,也未定义对 vtable 的引用

Undefined reference to vtable even when virtual methods have been implemented

我正在尝试编译最新版本的 QEmacs(Emacs 的微型版本):

https://github.com/dmacvicar/qemacs

一切正常,我有所需的库,包括 Qt,但在链接阶段,链接器出错 undefined reference to vtable。我在 Whosebug 上查看了几个问题和答案,我检查并验证了所有三个虚拟方法在 qt.cpp 中都有适当的空白实现。所以有什么问题?

gcc -g -Wl,-E -o qe_g .objs/qe.o .objs/parser.o .objs/charset.o .objs/buffer.o .objs/input.o .objs/display.o .objs/util.o .objs/hex.o .objs/list.o .objs/cutils.o .objs/extras.o .objs/variables.o .objs/qt.o .objs/tty.o .objs/kmap.o .objs/unicode_join.o .objs/arabic.o .objs/indic.o .objs/qfribidi.o .objs/charsetjis.o .objs/charsetmore.o .objs/unihex.o .objs/bufed.o .objs/clang.o .objs/xml.o .objs/htmlsrc.o .objs/lisp.o .objs/makemode.o .objs/markdown.o .objs/orgmode.o .objs/perl.o .objs/script.o .objs/extra-modes.o .objs/shell.o .objs/dired.o .objs/latex-mode.o .objs/archive.o .objs/x11.o .objs/html.o .objs/docbook.o .objs/qeend.o libqhtml/libqhtml.a -ldl `pkg-config --libs Qt5Gui Qt5Core Qt5Widgets` -lstdc++ -lpthread -lm -lXv -L/usr/X11R6/lib -lXext -lX11 -L./libqhtml -lqhtml -DQT_NO_DEBUG_OUTPUT
.objs/qt.o: In function `QEQtView::~QEQtView()':
/home/ho1/projects/qemacs/qt.cpp:197: undefined reference to `vtable for QEQtView'
.objs/qt.o: In function `QEQtView::QEQtView(QEQtContext*, QWidget*)':
/home/ho1/projects/qemacs/qt.cpp:192: undefined reference to `vtable for QEQtView'
.objs/qt.o: In function `QEQtApplication::QEQtApplication()':
/home/ho1/projects/qemacs/qt.cpp:525: undefined reference to `vtable for QEQtApplication'
collect2: error: ld returned 1 exit status
make: *** [qe_g] Error 1

这是虚方法的实现:

# Line 192
QEQtView::QEQtView(QEQtContext *ctx, QWidget *parent)
    : QWidget(parent),
      _ctx(ctx),
      _repaints(0)
{
//setAttribute(Qt::WA_OpaquePaintEvent);
}

# Line 197
QEQtView::~QEQtView()
{
}

....
# Line 525
QEQtApplication::QEQtApplication()
        : QApplication(qe_state.argc, qe_state.argv)
{
}

这是 nm 的输出:

$ nm -C .objs/qt.o | grep QEQtView::
0000000000000850 T QEQtView::closeEvent(QCloseEvent*)
0000000000001340 T QEQtView::mouseEvent(QMouseEvent*)
0000000000001c90 T QEQtView::paintEvent(QPaintEvent*)
00000000000000e0 T QEQtView::wheelEvent(QWheelEvent*)
0000000000001c40 T QEQtView::resizeEvent(QResizeEvent*)
0000000000001310 T QEQtView::slotSetClip(int, int, int, int)
0000000000000f60 T QEQtView::slotDrawText(QFont const&, int, int, QString const&, QColor const&, bool)
0000000000000200 T QEQtView::keyPressEvent(QKeyEvent*)
0000000000000f30 T QEQtView::slotSetCursor(int, int, int, int)
00000000000014e0 T QEQtView::mouseMoveEvent(QMouseEvent*)
00000000000014c0 T QEQtView::mousePressEvent(QMouseEvent*)
00000000000014d0 T QEQtView::mouseReleaseEvent(QMouseEvent*)
0000000000001160 T QEQtView::slotFillRectangle(int, int, int, int, QColor const&, bool)
0000000000001bd0 T QEQtView::slotResizeDoubleBuffer(QSize const&)
00000000000012c0 T QEQtView::slotFlush()
0000000000000eb0 T QEQtView::QEQtView(QEQtContext*, QWidget*)
0000000000000eb0 T QEQtView::QEQtView(QEQtContext*, QWidget*)
00000000000000b0 T QEQtView::~QEQtView()
0000000000000080 T QEQtView::~QEQtView()
0000000000000080 T QEQtView::~QEQtView()
00000000000000d0 T non-virtual thunk to QEQtView::~QEQtView()
00000000000000a0 T non-virtual thunk to QEQtView::~QEQtView()
0000000000000000 r QEQtView::closeEvent(QCloseEvent*)::__PRETTY_FUNCTION__

$ nm -C .objs/qt.o | grep QEQtApplication::
00000000000014f0 T QEQtApplication::QEQtApplication()
00000000000014f0 T QEQtApplication::QEQtApplication()

问题出在构建过程,而不是实际的源代码。我已经用 cmake 构建了这个项目,它很好。