我只想启动一个简单的 QT 应用程序。我有main.cpp
,mainwindow.h
并且mainwindow.cpp
。但是,当我将代码复制并粘贴到 中时,这是有效的mainwindow.h
,mainwindow.cpp
我main.cpp
收到神秘的链接器错误。
什么有效
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets/QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
private:
Ui::MainWindow* ui;
};
#endif
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
{
ui = new Ui::MainWindow;
ui->setupUi(this);
}
MainWindow::~MainWindow() { delete ui; }
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
什么不起作用
//main.cpp
#include <QApplication>
#include "ui_mainwindow.h"
#include <QtWidgets/QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
private:
Ui::MainWindow* ui;
};
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
{
ui = new Ui::MainWindow;
ui->setupUi(this);
}
MainWindow::~MainWindow() { delete ui; }
int main(int argc, char **argv)
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
这在链接过程中给我带来了以下错误:
/usr/bin/ld: /tmp/ccX909s9.ltrans1.ltrans.o: in function `MainWindow::~MainWindow()':
<artificial>:(.text+0x3): undefined reference to `vtable for MainWindow'
/usr/bin/ld: /tmp/ccX909s9.ltrans1.ltrans.o: in function `main':
<artificial>:(.text.startup+0x4a): undefined reference to `vtable for MainWindow'
经过一番搜索后,这个非常详细的错误意味着某个地方有一个虚拟函数未实现。我真的很努力地想明白这一切在这里有何重要意义。
作为参考,我是一名传统的 C 程序员,从我的角度来看,这些程序应该是相同的。我真的很想了解编译器此时正在寻找什么神奇的胡言乱语。
正如评论中所澄清的那样,这两个程序实际上并不相同:在第一种情况下,没有创建隐藏在宏内的方法
Q_OBJECT
,其中一些是虚拟的(metaObject
是其中最重要的方法)。这应该是moc
(元对象编译器)的作用。您得到的是声明但未实现的虚拟方法。
与上面的不同,您的头文件+源文件方法确实会导致头文件被 moc'd,这会使用所需的方法创建一个单独的源文件。在 Qt Creator 或安装了 Qt VS 工具扩展的 Visual Studio 中,一切都会自动发生;您不需要执行任何操作来配置这些步骤(在其他开发环境中可能是这种情况)。
在 Visual studio vanilla(我使用过 Qt 并手动配置所有内容的唯一环境)中,您必须手动配置自定义构建步骤,然后包含生成的源文件以进行编译。手动配置所有内容有点令人头疼,但这可以让您轻松找出错误。
注意:正如我在评论中所说,
Q_OBJECT
宏对于QObject
. 如果您没有声明任何会修改类的元对象(信号、槽、属性、接口...)的内容,则可以跳过该宏。AFAICT,您问题中的代码不需要
Q_OBJECT
,因此您问题中的 main.cpp-only 代码片段在您简单删除它后应该可以工作。