the Meta-Object Compiler (moc)

时间:2022-05-06 20:26:36

the Meta-Object Compiler (moc)

元对象编译器是处理Qt的C++扩展的程序。

moc工具读取C++头文件,如果它找到一个或者多个类声明包含Q_OBJECT宏。它生为那些类成一个包含元对象代码的C++源文件。元对象代码是信号与槽机制,运行时信息和动态属性系统所必需的。

moc生成的C++源文件在类的实现过程中必需进行编译和连接。

如果你用qmake创建makefiles,包含的创建规则在需要的时候调用moc,所以你不用直接使用moc。

Usage

moc典型的用法,输入文件包含的类声明:

class MyClass : publicQObject

{

Q_OBJECT

public:

MyClass(QObject*parent =0);

~MyClass();

signals:

void mySignal();

publicslots:

void mySlot();

};

除了以上显示的信号与槽机制外,moc实现对象属性如下例子。Q_PROPERTY()宏声明了一个对象属性, Q_ENUMS()在类中声明了一个枚举类型,可以用在属性系统中。

在下面的例子,我们声明了一个枚举属性,一个获取属性的方法priority() 和设置属性的方法setPriority().。

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority)
    Q_ENUMS(Priority)
 
public:
    enum Priority { High, Low, VeryHigh, VeryLow };
 
    MyClass(QObject *parent =0);
    ~MyClass();
 
    void setPriority(Priority priority) { m_priority = priority; }
    Priority priority() const { return m_priority; }
 
private:
    Priority m_priority;
};

Q_FLAGS() 宏声明一个可以用作标记的枚举值。另外一个宏 Q_CLASSINFO(), 允许你给类的元对象添加额外的name/value对信息。

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author","Oscar Peterson")
    Q_CLASSINFO("Status","Active")
 
public:
    MyClass(QObject *parent =0);
    ~MyClass();
};

moc生成的文件必须和程序中的其他C++源文件一样进行编译和链接;否则,在在生成的链接阶段将失败。如果你使用qmake,这将会自动完成。当qmake允许起来,它解析工程的头文件和生成创建规则以为那些包含 Q_OBJECT宏的文件进行调用moc。

如果类在myclass.h中声明,moc生成 的文件为moc_myclass.cpp。这个文件一样进行编译,在windows上生成的目标文件moc_myclass.obj。这个目标文件在程序生成过程都需要进行连接的。

Writing Make Rules for Invoking moc

为了简单的测试程序,建议自动运行moc。通过添加规则到程序的makefile,可以在需要的时候很好的运行moc和处理moc的生成文件。

我们建议使用qmake 的makefile生成工具创建makefile。这个工具生成moc需要的所有操作的makefile。

如果你想创建自己的makefile,这里有一些如何包含moc操作的提示。

对于头文件中 Q_OBJECT宏声明,如果你只用GNU make这里有一个很有用的makefile规则:

moc_%.cpp: %.h
        moc $(DEFINES) $(INCPATH) $<-o $@

如果你想写的更灵活,你可以用如下的单独的规则格式:

moc_foo.cpp: foo.h
        moc $(DEFINES) $(INCPATH) $<-o $@

你必须记得添加moc_foo.cpp到你的SOURCES 变量和moc_foo.o 或moc_foo.obj到你的OBJECTS 变量。

所有的例子都假设$(DEFINES) 和 $(INCPATH) 展开到传递到C++编译器的define和include路径选项。这些都是moc在进行源文件的预处理时需要的。

我们喜欢把源文件命名为.cpp。其实也可以用其他扩展,如.c,.cc,.CC,.cxx和.c++。

对于.cpp文件中的r Q_OBJECT宏声明,我们建议makefile规则如下:

foo.o: foo.moc
 
foo.moc: foo.cpp
        moc $(DEFINES) $(INCPATH) -i $<-o $@

这保证了在编译foo.cpp之前允许moc,你可以把:

#include "foo.moc"

放在foo.cpp的末尾。所有类声明都已完全可知的地方。

Command-Line Options

以下是moc支持命令行选项:

Option

Description

-o<file>

Write output to <file> rather than to standard output.

-f[<file>]

Force the generation of an #include statement in the output. This is the default for header files whose extension starts with H or h. This option is useful if you have header files that do not follow the standard naming conventions. The <file> part is optional.

-i

Do not generate an #include statement in the output. This may be used to run the moc on on a C++ file containing one or more class declarations. You should then #include the meta-object code in the .cpp file.

-nw

Do not generate any warnings. (Not recommended.)

-p<path>

Makes the moc prepend <path>/ to the file name in the generated #include statement.

-I<dir>

Add dir to the include path for header files.

-E

Preprocess only; do not generate meta-object code.

-D<macro>[=<def>]

Define macro, with optional definition.

-U<macro>

Undefine macro.

@<file>

Read additional command-line options from <file>. Each line of the file is treated as a single option. Empty lines are ignored. Note that this option is not supported within the options file itself (i.e. an options file can't "include" another file).

-h

Display the usage and the list of options.

-v

Display moc's version number.

-Fdir

Mac OS X. Add the framework directory dir to the head of the list of directories to be searched for header files. These directories are interleaved with those specified by -I options and are scanned in a left-to-right order (see the manpage for gcc). Normally, use -F /Library/Frameworks/

你可以显示的告诉moc不要解析头文件中的某些部分。moc定义了预处理宏 Q_MOC_RUN. 。

以下代码将被moc忽略。

#ifndef Q_MOC_RUN
    ...
#endif

Diagnostics

在 Q_OBJECT 类声明中,moc会给出一些危险或者非法的创建的警告。

如果在程序生成的最后阶段发生连接错误,说YourClass::className() 没有定义或YourClass缺少虚函数表vtable。一定是出现了某些错误。最可能的是,你忘记编译或 #include包含了moc生成的C++源文件,或者在连接命令忘记包含目标文件。如果你用qmake,试着重新运行更新makefile,这就行了。

Limitations

moc不能处理所有的C++。最主要的问题是模板类不能用信号或槽。例如:

class SomeTemplate<int> : public QFrame
{
    Q_OBJECT
    ...
 
signals:
    void mySignal(int);
};

次要的是,以下的结构都是非法的。他们都选择了我们认为是更好的,所以去掉这些限制对我们来说并不是优先选择。

MultipleInheritance Requires QObject to Be First

如果使用多继承,moc假定第一个被继承的类是 QObject.的子类。确保只有第一个被继承的类是QObject.。

// correct
class SomeClass : public QObject,public OtherClass
{
    ...
};

不支持对QObject的虚拟继承。

FunctionPointers Cannot Be Signal or Slot Parameters

在大部分情况,你可以考虑使用函数指针作为信号或槽的参数,我们觉得继承是一个号的替代选择。如下例子有语法错误:

class SomeClass : public QObject
{
    Q_OBJECT
 
publicslots:
    void apply(void (*apply)(List *, void *), char *); // WRONG
};

我们可以进行如下变通:

typedef void (*ApplyFunction)(List *, void *);
 
class SomeClass : public QObject
{
    Q_OBJECT
 
publicslots:
    void apply(ApplyFunction, char *);
};

最好还是用继承或虚函数替代函数指针。

Enumsand Typedefs Must Be Fully Qualified for Signal and Slot Parameters

当检查参数的签名时, QObject::connect() 逐字地的进行比较数据类型。因此, Alignment和 Qt::Alignment 被当成不同的类型。为了解决这个问题,当声明信号和槽,或者建立connection时,确保取得数据类型的完全资格。

class MyClass : public QObject
{
    Q_OBJECT
 
    enum Error {
        ConnectionRefused,
        RemoteHostClosed,
        UnknownError
    };
 
signals:
    void stateChanged(MyClass::Error error);
};

NestedClasses Cannot Have Signals or Slots

这是个结构不好的例子:

class A
{
public:
    class B
    {
        Q_OBJECT
 
    publicslots:   // WRONG
        void b();
    };
};

Signal/Slotreturn types cannot be references

信号和槽可以有返回类型,但是信号或槽返回引用会被当成返回void。

Only Signals and Slots May Appear in the signals and slots Sections of aClass

moc会抱怨,如果你试图将信号和槽意外的结构放在信号和槽段。

http://blog.csdn.net/hai200501019/article/details/9157149