您的位置:首页 > 移动开发 > Objective-C

the Meta-Object Compiler (moc)

2016-02-01 19:49 447 查看
theMeta-ObjectCompiler(moc)

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

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

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

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

Usage

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

classMyClass:publicQObject

{

Q_OBJECT

public:

MyClass(QObject*parent=0);

~MyClass();

signals:

voidmySignal();

publicslots:

voidmySlot();

};

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

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

classMyClass:publicQObject

{

Q_OBJECT

Q_PROPERTY(PrioritypriorityREADpriorityWRITEsetPriority)

Q_ENUMS(Priority)


public:

enumPriority{High,Low,VeryHigh,VeryLow};


MyClass(QObject*parent=0);

~MyClass();


voidsetPriority(Prioritypriority){m_priority=priority;}

Prioritypriority()const{returnm_priority;}


private:

Prioritym_priority;

};


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

classMyClass:publicQObject

{

Q_OBJECT

Q_CLASSINFO("Author","OscarPeterson")

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。这个目标文件在程序生成过程都需要进行连接的。

WritingMakeRulesforInvokingmoc

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

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

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

对于头文件中Q_OBJECT宏声明,如果你只用GNUmake这里有一个很有用的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文件中的rQ_OBJECT宏声明,我们建议makefile规则如下:

foo.o:foo.moc


foo.moc:foo.cpp

moc$(DEFINES)$(INCPATH)-i$<-o$@


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

#include"foo.moc"


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

Command-LineOptions

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

Option

Description

-o<file>

Writeoutputto<file>ratherthantostandardoutput.

-f[<file>]

Forcethegenerationofan#includestatementintheoutput.ThisisthedefaultforheaderfileswhoseextensionstartswithHorh.Thisoptionisusefulifyouhaveheaderfilesthatdonotfollowthestandardnamingconventions.The<file>partisoptional.

-i

Donotgeneratean#includestatementintheoutput.ThismaybeusedtorunthemocononaC++filecontainingoneormoreclassdeclarations.Youshouldthen#includethemeta-objectcodeinthe.cppfile.

-nw

Donotgenerateanywarnings.(Notrecommended.)

-p<path>

Makesthemocprepend<path>/tothefilenameinthegenerated#includestatement.

-I<dir>

Adddirtotheincludepathforheaderfiles.

-E

Preprocessonly;donotgeneratemeta-objectcode.

-D<macro>[=<def>]

Definemacro,withoptionaldefinition.

-U<macro>

Undefinemacro.

@<file>

Readadditionalcommand-lineoptionsfrom<file>.Eachlineofthefileistreatedasasingleoption.Emptylinesareignored.Notethatthisoptionisnotsupportedwithintheoptionsfileitself(i.e.anoptionsfilecan't"include"anotherfile).

-h

Displaytheusageandthelistofoptions.

-v

Displaymoc'sversionnumber.

-Fdir

MacOSX.Addtheframeworkdirectorydirtotheheadofthelistofdirectoriestobesearchedforheaderfiles.Thesedirectoriesareinterleavedwiththosespecifiedby-Ioptionsandarescannedinaleft-to-rightorder(seethemanpageforgcc).Normally,use-F/Library/Frameworks/

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

以下代码将被moc忽略。

#ifndefQ_MOC_RUN

...

#endif


Diagnostics

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

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

Limitations

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

classSomeTemplate<int>:publicQFrame

{

Q_OBJECT

...


signals:

voidmySignal(int);

};


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

MultipleInheritanceRequiresQObjecttoBeFirst

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

//correct

classSomeClass:publicQObject,publicOtherClass

{

...

};


不支持对QObject的虚拟继承。

FunctionPointersCannotBeSignalorSlotParameters

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

classSomeClass:publicQObject

{

Q_OBJECT


publicslots:

voidapply(void(*apply)(List*,void*),char*);//WRONG

};


我们可以进行如下变通:

typedefvoid(*ApplyFunction)(List*,void*);


classSomeClass:publicQObject

{

Q_OBJECT


publicslots:

voidapply(ApplyFunction,char*);

};


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

EnumsandTypedefsMustBeFullyQualifiedforSignalandSlotParameters

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

classMyClass:publicQObject

{

Q_OBJECT


enumError{

ConnectionRefused,

RemoteHostClosed,

UnknownError

};


signals:

voidstateChanged(MyClass::Errorerror);

};


NestedClassesCannotHaveSignalsorSlots

这是个结构不好的例子:

classA

{

public:

classB

{

Q_OBJECT


publicslots://WRONG

voidb();

};

};


Signal/Slotreturntypescannotbereferences

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

OnlySignalsandSlotsMayAppearinthesignalsandslotsSectionsofaClass

moc会抱怨,如果你试图将信号和槽意外的结构放在信号和槽段。
http://blog.csdn.net/hai200501019/article/details/9157149
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: