Q_OBJECT的一些注意事项

今天被 Qt的一个编译错误弄得心烦透了。原来我想写如下结构的代码。

#include <iostream>
#include <QtCore>
#include <QApplication>
using namespace std;

class Manager:public QObject
{
    Q_OBJECT
public:
    Manager(QObject *parent = 0);

private slots:
    void doSomething();
signals:
    void happenSomething();
};

Manager::Manager(QObject *parent): QObject(parent){}
void Manager::doSomething()
{
    //doSomething
}

int main()
{
    return 0;
}

这样出现了

/home/gikieng/oop/qt_test/QOBJECT/main.cpp:18: error: undefined reference to `vtable for Manager'
这样的错误,上网搜了一下,有人说在在cpp文件中,宏Q_OBJECT不给展开。好吧,我另外用一个.h文件把那些类定义装起来。

#ifndef MANAGER_H
#define MANAGER_H
#include <QtCore>
#include <QApplication>

class Manager:public QObject
{
    Q_OBJECT
public:
    Manager(QObject *parent = 0);

private slots:
    void doSomething();
signals:
    void happenSomething();
};


Manager::Manager(QObject *parent): QObject(parent){}
void Manager::doSomething()
{
    //doSomething
}

#endif // MANAGER_H

然后又出现了这个奇皅错误:

/home/gikieng/oop/qt_test/QOBJECT/manager.h:21: error: multiple definition of `Manager::doSomething()'
重复定义。。。

我明明上面是声明,下面是定义,怎么会出现重复定义的错误。

然后又是上网狂搜,都是说重复引用头文件引起的,可是我也加#ifndef 进行保护了。

查了一下宏Q_OBJECT。终于有点想法了。

只有在类里面加入了Q_OBJECT宏,才能使用slots和signals。

在预编译的过程中会有一个manager.moc文件的生成,这个应该是Q_OBJECT的展开,想到之前写的声明某个slot而没有进行定义slot时,会可以看到一个文件。

里面有这个么段:

void Manager::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        Manager *_t = static_cast<Manager *>(_o);
        switch (_id) {
        case 0: _t->happenSomething(); break;
        case 1: _t->doSomething(); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        void **func = reinterpret_cast<void **>(_a[1]);
        {
            typedef void (Manager::*_t)();
            if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Manager::happenSomething)) {
                *result = 0;
            }
        }
    }
    Q_UNUSED(_a);
}
难道对应一个头文件都会展开一个moc文件,在moc中认不出定义和声明了?

我尝试把所有类外部定义都放入了类内定义。

这下没有出错了。

在header文件中声明类加入Q_OBJECT, 在cpp文件中定义。

也没有出错。
这里面涉及到元对象的技术。明天再看一下。


应该注意:

用到Q_OBJECT宏的类不应该放到cpp文件中声明和定义。

应该在.h文件中声明,然后在.cpp文件中定义。

#include "xuwidget.h" #include "ui_xuwidget.h" #include "stdio.h" #include "stdlib.h" xuWidget::xuWidget(QWidget *parent) : QWidget(parent), ui(new Ui::xuWidget),openflage(false) { ui->setupUi(this); this->setWindowTitle("XCOM V1.4"); SerialPort = new QSerialPort(this); } xuWidget::~xuWidget() { delete ui; } //清除接收 void xuWidget::on_ClearRecvPushButton_clicked() { ui->RecvDataPlainTextEdit->clear(); } //清除发送 void xuWidget::on_CleanSendPushButton_clicked() { ui->SendDataPlainTextEdit->clear(); } //打开或关闭串口 void xuWidget::on_OpenAndCloseComBox_clicked() { if(!openflage) { ReadCurrentSettingInfo(); if(SerialPort->open(QIODevice::ReadWrite)) { openflage = true; ui->OpenAndClosePushButton->setText("关闭串口"); } } else { SerialPort->close(); ui->OpenAndClosePushButton->setText("打开串口"); openflage = false; } } //读取当前串口助手配置信息 void xuWidget::ReadCurrentSettingInfo() { //设置端口名称 SerialPort->setPortName(ui->comboBox->currentText()); //读取波特率 SerialPort->setBaudRate(ui->BaudComBox->currentText().toInt()); //设置停止位 switch(ui->StopBitComBox->currentText()) { case 0:SerialPort->setStopBits(QSerialPort::OneStop);break; case 1:SerialPort->setStopBits(QSerialPort::OneAndHalfStop);break; case 2:SerialPort->setStopBits(QSerialPort::TwoStop);break; } //设置数据位 switch(ui->DataBitComBox->currentText()) { case 0:SerialPort->setDataBits(QSerialPort::Data8);break; case 1:SerialPort->setDataBits(QSerialPort::Data7);break; case 2:SerialPort->setDataBits(QSerialPort::Data6);break; case 3:SerialPort->setDataBits(QSerialPort::Data5);break; } //设置奇偶校验 switch(ui->EvenAndOddCheckBitComBox->currentText()) { case 0:SerialPort->setParity(QSerialPort::NoParity);break; case 1:SerialPort->setParity(QSerialPort::OddParity);break; case 2:SerialPort->setParity(QSerialPort::EvenParity);break; } } 这段代码哪里有错误
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值