c++ - Qt5 未定义对 vtable CMake 构建问题的引用
问题描述
我决定用 CMake 构建一些计算器,但由于某种原因它失败了,但它看起来是正确的。我有一个 set(CMAKE_AUTOMOC ON) 规则,但是,什么是 vtable?我不能简单地构建它...下面有所有项目文件
CMakeLists.txt
cmake_minimum_required(VERSION 3.1.0)
project(calculator)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC_ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
include_directories("./include")
add_executable(${PROJECT_NAME} calculator.cpp main.cpp)
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Widgets)
计算器.hpp
#ifndef CALCULATOR_HPP
# define CALCULATOR_HPP
#include <QtWidgets/QWidget>
#include <QVector>
#include <QLCDNumber>
#include <QPushButton>
class Calculator : public QWidget {
Q_OBJECT
public:
Calculator(QWidget *pwgt = nullptr);
QPushButton *createButton(QString const &rhs);
void calculate();
private:
QLCDNumber *_plcd;
QString _strDisplay;
QVector<QString> _strVector;
public slots:
void buttonClicked();
};
#endif
计算器.cpp
#include <calculator.hpp>
#include <QGridLayout>
Calculator::Calculator(QWidget *pwgt) : QWidget(pwgt) {
QGridLayout *gridObj = new QGridLayout();
_plcd = new QLCDNumber(12);
_plcd->setMode(QLCDNumber::Dec);
_plcd->setSegmentStyle(QLCDNumber::Flat);
_plcd->setMinimumSize(150, 50);
//_wgtPtr = (!_pwgt) ? new QWidget() : pwgt;
QChar calcChars[4][4] = { {'7', '8', '9', '/'},
{'4', '5', '6', '*'},
{'1', '2', '3', '-'},
{'0', '.', '=', '+'}};
gridObj->addWidget(_plcd, 0, 0);
gridObj->addWidget(createButton("CE"), 1, 3);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j)
gridObj->addWidget(createButton(calcChars[i][j]), i + 2, j);
}
setLayout(gridObj);
}
QPushButton *Calculator::createButton(QString const &rhs) {
QPushButton *calcButton = new QPushButton(rhs);
calcButton->setMinimumSize(40, 40);
connect(calcButton, SIGNAL(clicked()), SLOT(buttonClicked()));
return (new QPushButton(rhs));
}
void Calculator::buttonClicked() {
QString match = dynamic_cast<QPushButton *>(sender())->text();
QRegExp regMatch("[0-9]");
if (!match.compare("CE")) {
_strVector.clear();
_strDisplay.clear();
_plcd->display("0");
} else if (match.contains(regMatch)) {
_strDisplay.push_back(match);
_plcd->display(_strDisplay.toDouble());
} else if (!match.compare(".")) {
_strDisplay.push_back(match);
_plcd->display(_strDisplay.toDouble());
} else {
_strVector.push_back(_strDisplay);
if (_strVector.size() > 1) {
calculate();
_strVector.clear();
_strVector.push_back(_strDisplay);
if (match.compare("="))
_strVector.push_back(match);
} else {
_strVector.push_back(_strDisplay);
_strDisplay.clear();
_plcd->display("0");
}
}
}
void Calculator::calculate() {
double rValue = _strVector.back().toDouble();
_strVector.pop_back();
QString operCalc = _strVector.back();
_strVector.pop_back();
double lValue = _strVector.back().toDouble();
if (!operCalc.compare("+"))
rValue += lValue;
if (!operCalc.compare("-"))
rValue -= lValue;
if (!operCalc.compare("/"))
rValue /= lValue;
if (!operCalc.compare("*"))
rValue *= lValue;
_strDisplay.number(rValue);
_plcd->display(_strDisplay.toDouble());
}
和main.cpp
#include <calculator.hpp>
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Calculator *obj = new Calculator;
obj->resize(230, 200);
obj->setWindowTitle("QtCalculator");
obj->show();
return (app.exec());
}
这是文件层次结构
|--> CMakeLists.txt
|
|--> calculator.cpp
|
|--> main.cpp
|
|--> include
|
|--> calculator.hpp
这是一个构建输出(在 CLion IDE 中)
====================[ Build | all | Debug ]=====================================
/snap/clion/162/bin/cmake/linux/bin/cmake --build /home/lchantel/train_01Qt/cmake-build-debug --target all -- -j 3
[ 20%] Automatic MOC for target calculator
[ 20%] Built target calculator_autogen
Scanning dependencies of target calculator
[ 40%] Building CXX object CMakeFiles/calculator.dir/calculator_autogen/mocs_compilation.cpp.o
[ 60%] Building CXX object CMakeFiles/calculator.dir/calculator.cpp.o
[ 80%] Building CXX object CMakeFiles/calculator.dir/main.cpp.o
[100%] Linking CXX executable calculator
/usr/bin/ld: CMakeFiles/calculator.dir/calculator.cpp.o: in function `Calculator::Calculator(QWidget*)':
/home/lchantel/train_01Qt/calculator.cpp:4: undefined reference to `vtable for Calculator'
/usr/bin/ld: /home/lchantel/train_01Qt/calculator.cpp:4: undefined reference to `vtable for Calculator'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/calculator.dir/build.make:126: calculator] Error 1
make[1]: *** [CMakeFiles/Makefile2:84: CMakeFiles/calculator.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
解决方案
您的 CMake 代码需要一些工作:
- 永远不要
include_directories
在 CMake中使用。改为使用target_include_directories
。 - 始终使用或with之一
PRIVATE
来避免奇怪的遗留行为。PUBLIC
INTERFACE
target_link_libraries
- 用术语定义目标
${PROJECT_NAME}
很奇怪,更长,并且使您的代码可读性降低,没有任何好处。没有令人信服的理由让它们保持耦合,并且项目名称很少更改。 - 永远不要
CMAKE_CXX_COMPILER
在你的 CMakeLists.txt 中设置 - 更喜欢编译特性而不是设置
CMAKE_CXX_STANDARD
。 - 我严重怀疑您使用的是 CMake 3.1.0。切勿将版本设置为低于您正在使用/测试的版本。
- 你有一个杂散的下划线
CMAKE_AUTOUIC_ON
请改用此构建:
cmake_minimum_required(VERSION 3.16)
project(calculator)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 REQUIRED Core Widgets)
add_executable(calculator calculator.cpp main.cpp include/calculator.hpp)
target_link_libraries(calculator PRIVATE Qt5::Core Qt5::Widgets)
target_include_directories(calculator PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_features(calculator PRIVATE cxx_std_11)
您看到 vtable 错误的原因是看moc
不到您的include/calculator.hpp
标题,因为它未列为add_executable
.
推荐阅读
- google-apps-script - 从多个选项卡到 VLOOKUP 汇总列的脚本 从每个选项卡中提取数据 wrt 值
- spring - 是否可以将最后一个元素与 JPA 和 Spring boot 分组
- typescript - RXJS:在继续之前获取可观察的结果
- elasticsearch - Vega-Lite / Kibana 管理 URL 对象的区别
- game-development - 应用发明者:只要按下按钮,如何移动精灵?
- azure-devops - Azure DevOps 中 TFVC 的最大存储大小是多少?
- c++ - 如何从 C++ 服务访问 Google 联系人?
- java - 加载错误的 PDF 时捕获 PDFBox 警告
- c - 如何在 Eclipse 中运行/打开 ac 文件
- iis - 在 IIS 中设置 ASP.Net Core 2.1V