#c #qt #cmake #qt5
Вопрос:
я решил создать какой-то калькулятор с помощью 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)
калькулятор.ГЭС
#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 amp;rhs);
void calculate();
private:
QLCDNumber *_plcd;
QString _strDisplay;
QVector<QString> _strVector;
public slots:
void buttonClicked();
};
#endif
calculator.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() : pw>
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 amp;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
Комментарии:
1. Спасибо за предоставление полного примера, который позволил мне воспроизвести вашу ошибку.
Ответ №1:
Ваш код CMake нуждается в некоторой доработке:
- Никогда не используйте
include_directories
в CMake никогда. Используйтеtarget_include_directories
вместо этого. - Всегда используйте один из
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
.