Qt的MOC与头文件内实现?Qt的MOC与头文件内实现?(Qt moc with implement

2019-05-12 01:54发布

是否可以告诉Qt的MOC,我想申报类,并在一个单独的文件执行它,而不是分裂的上了h和.cpp文件?

Answer 1:

如果你想声明,并在您实现一个QObject子类的cpp文件,你必须手动包括商务部的文件。

例如:(文件main.cpp中)

struct SubObject : QObject
{
    Q_OBJECT
};

//...

#include "main.moc"

你必须重新运行MOC( make qmake加入后) #include声明。



Answer 2:

TL; DR

是的,如果你只是在谈论你自己写的(而不是那些由商务部生成)的文件。 你不需要做什么特别的。

如果你希望明确包括在你写的文件的moc输出,还有一个情况下,你必须做,一个情况下,你可能希望这样做。 让我们假设MyObject类中声明MyObject.h和你对它的定义中给出MyObject.cpp

  1. MyObject.moc 必须包括在年底 MyObject.cpp 当且仅当你声明任何Q_OBJECT中的类MyObject.cpp

  2. moc_MyObject.cpp 可以 随时随地包含 MyObject.cpp减半在项目的翻译单元数量。 这只是一个构建时的优化。 如果你不这样做, moc_MyObject.cpp将另行编制。

每次添加或删除Q_OBJECT从任何来源或头文件中的宏,或者您添加或删除的moc输出的明确夹杂在这些文件中,则必须重新运行QMAKE / cmake的。

重新运行QMAKE / cmake的Qt Creator中,只需在顶级项目上单击右键,然后从上下文菜单中运行的qmake运行cmake。

简单的答案

一个例子基于QMAKE,Qt的项目可能包括三个文件,如下所示:

# test.pro
QT       += core
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += myobject.h

// main.cpp
#include "myobject.h"

int main() {
  MyObject obj;
  obj.staticMetaObject; // refer to a value defined in moc output
  return 0;
}

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>

class MyObject : public QObject {
   Q_OBJECT
public:
   MyObject() {}
   Q_SLOT void aSlot() {}
};

#endif // MYOBJECT_H

它没有做太多,但它肯定是有效的。 除此之外,构建系统联系我们的项目有不同的库,有两个具体项目的翻译单位 : main.cppmoc_myobject.cpp

即使它看起来的整个实施MyObject是在头文件,它真的不是。 该Q_OBJECT宏声明的实施的某些位将是不确定的,如果不是对MOC-产生的定义。

如何MOC进入了吗? 当项目初建时,元软件包工具-无论是QMAKE或CMake的-扫描存在的所有C ++输入文件Q_OBJECT宏。 那些含有它,给予特殊待遇。 在这个例子中的项目, myobject.h包含Q_OBJECT并通过MOC加工成moc_myobject.cpp 。 后者被添加到由C ++编译器编译的源的列表。 它,只是概念上的,因为如果你有SOURCES += moc_myobject.cpp.pro文件。 当然,你应该这样一行从未添加到.pro文件。

现在可以看到的整个实施MyObject掌握在两个文件: myobject.hmoc_myobject.cppmyobject.h可以包含在许多翻译单元,你的愿望-因为有这将违反一个定义规则没有超出级(独立)的定义。 构建体系将moc_myobject.cpp作为一个单一的,独立的翻译单位-这是所有采取的为你服务。

因此,你的目标是达到了,没有力气都:你有什么特别要做把整个实施MyObject -保存,交通部产生位-为头文件。 它可能会延长编译时间,但在其他无害的。

一个规则,违反法

它违反了一个定义规则 ,准确的,因而产生一个无效的C ++程序。

现在,你可能会认为得到“聪明”,强行包括商务部输出到头文件。 该QMAKE / cmake的/ QBS将被容纳,并且将检测到这一点,并不会单独再处理编译通过MOC输出,你已经做到了。

因此,假设是,在上述项目中,你改变了myobject.h内容如下:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>

class MyObject : public QObject {
   Q_OBJECT
public:
   MyObject() {}
   Q_SLOT void aSlot() {}
};

#include "moc_myobject.cpp"
#endif // MYOBJECT_H

既然这样,该项目将仍然编译,看似履行其只是一个文件,它定义的全部的你的目标MyObject -你写的位,并且MOC产生的位,两者。 但是,这只是一个不太愉快的情况原因:内容moc_*.cpp仍然只在一个翻译单元-

假设,现在我们第二个源文件添加到我们的项目:

# test.pro
QT       += core
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h

// test.cpp
#include "myobject.h"

不多了。 它应该工作,即使它没有做太多,对不对?

可惜的是,它不会链接。 现在的内容moc_myobject.cpp是两个翻译单元的一部分。 由于moc_myobject.cpp的内心都充满了单机类成员的定义,这违反了一个定义规则 。 该规则授权独立定义可能只有一个目标之内出现在一个翻译单元 。 链接器,是这个规则的守护者,理所当然地抱怨。

在包括在.cpp文件MOC输出

正如在TL提到; DR,没有上述排除了源(的.cpp)文件的moc输出的显式包含,在特定情况下。

鉴于“了foo.h”和“Foo.cpp中”,并通过QMAKE或CMake的管理项目,构建系统会直接moc产生高达两个输出:

  1. moc_foo.cppfoo.h当且仅当 foo.h含有Q_OBJECT宏。

  2. foo.mocfoo.cpp当且仅当 foo.cpp包含#include "foo.moc"

让我们来详细探讨为什么你想为包括一个在.cpp文件。

包括xxx.moc

有时,特别是在之前的C ++ 11和Qt 5天,说到方便的只有一个翻译单元(源文件)内本地使用申报小帮手的QObject类。

写单文件,自包含的测试案例和示例计算器使用时,这也来得心应手。

假设你希望有人证明,在一个文件中,如何调用从事件循环槽:

// main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <cstdio>

QTextStream out(stdout);

class MyObject : public QObject {
  Q_OBJECT
public:
  MyObject() {}
  Q_SLOT void mySlot() { out << "Hello from " << __FUNCTION__ << endl; }
};

int main(int argc, char ** argv) {
  QCoreApplication app(argc, argv);
  MyObject obj;
  QMetaObject::invokeMethod(&obj, Qt::QueuedConnection, "mySlot");
  QMetaObject::invokeMethod(&app, Qt::QueuedConnection, "quit");
  return app.exec();
}

#include "main.moc"

由于MyObject是,只有在本地使用一个小班main.moc ,那就没有多大意义,把它定义成一个单独的头文件。 所述#include "main.moc"线将通过的qmake / cmake的被注意到,并且main.cpp将通过MOC供给,导致main.moc 。 由于main.moc定义的成员MyObject ,它必须被包括其中某个地方MyObject被声明。 由于声明中main.cpp ,你不能有main.moc是一个单独的翻译单元:它不会因编译到MyObject被未声明。 在声明的地方是内main.cpp ,接近尾声的地方。 这就是为什么它是一个安全的赌注,始终包括foo.moc在结束foo.cpp

聪明的读者现在问:怎么来moc_foo.cpp得到其成员,它定义的类的声明? 很简单:它明确包含它是从(这里:所产生的头文件foo.h )。 当然foo.moc不能这样做,因为它会通过乘法定义的一切打破单一定义规则foo.cpp

包括moc_xxx.cpp

在特别大的Qt项目,你可能有-平均-两个文件以及每个班两个平移单位:

  • MyObject.hMyObject.cpp是你写的文件。
  • MyObject.cppmoc_MyObject.cpp是翻译单元。

有可能通过明确包括减半的翻译单元数量moc_MyObject.cpp在某处MyObject.cpp

// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...


Answer 3:

我认为你能正常声明和实现在头文件中的类,而无需使用任何特殊,例如:

#include <QObject>

class MyClass : public QObject
{
  Q_OBJECT

  public:
     MyClass(QObject * parent)
     {
        // Constructor Content
     }

     methodExample()
     {
          // Method content
     }
};

在这之后,你的头文件添加到PRI文件,然后再执行qmake的,就是这样。 你必须从Qobject继承和实现,并宣布诠释他的.h文件中的类。



Answer 4:

我相信这是最好的方式。 它实际上是我现在该怎么构建我的所有对象。

Qt的4.8.7

Works.pro:

SOURCES += \
    main.cpp

HEADERS += \
    Window.h \
    MyWidget.h

main.cpp中

#include <QtGui>
#include "Window.h"

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    Window window;
    window.show();
    return app.exec();
}

在window.h

#ifndef WINDOW_H
#define WINDOW_H

#include <QtGui>
#include "MyWidget.h"

class Window : public QWidget
{
    Q_OBJECT

private:
    MyWidget *whatever;

public:
    Window()
    {
        QHBoxLayout *layout = new QHBoxLayout;
        setLayout(layout);

        whatever = new MyWidget("Screw You");
        layout->addWidget(whatever);

    }
};

#include "moc_Window.cpp"

#endif // WINDOW_H

MyWidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QtGui>

class MyWidget : public QLabel
{
    Q_OBJECT

public:
    MyWidget(QString text) : QLabel(text)
    {
        // Whatever
    }
};

#include "moc_MyWidget.cpp"

#endif // MYWIDGET_H

建立... QMAKE Works.pro

使



文章来源: Qt moc with implementations inside of header files?
标签: c++ qt moc