类classthe Meta-Object Compiler (moc)

本文是一篇关于类class的帖子

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 =);

~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 =);
    ~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 =);
    ~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会埋怨,如果你试图将信号和槽意外的结构放在信号和槽段。

文章结束给大家分享下程序员的一些笑话语录: 程序员的愿望
  有一天一个程序员见到了上帝.上帝: 小伙子,我可以满足你一个愿望.程序员: 我希望中国国家队能再次打进世界杯.
  上帝: 这个啊!这个不好办啊,你还说下一个吧!
  程序员: 那好!我的下一个愿望是每天都能休息6个小时以上.
  上帝: 还是让中国国家打进世界杯.

---------------------------------
原创文章 By
类和class
---------------------------------

上一篇:QQ能上,网页打不开


下一篇:使用DBUnit框架数据库插入特殊字符失败的查错经历