Qt之元对象编译器

元对象编译器(moc)是一个处理Qt c++扩展的程序。

moc工具读c++头文件,若它发现一个或更多的类声明包含这个O_OBJECT宏;它会提供这个类的包含元对象代码的c++源文件;除此之外,元对象代码还需要用于信号和槽机制,运行时类型信息和动态属性系统;

由moc生成的c++源文件必须被编译并与类的实现链接。

如果你使用qmake来创建你的makefile,构建规则会在需要的时候调用moc,所以你不需要直接使用moc。

信号槽机制

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = 0);
    ~MyClass();

signals:
    void mySignal();

public slots:
    void mySlot();
};

属性

moc还实现对象属性。Q_PROPERTY()宏声明一个对象属性,而Q_ENUMO)声明类中的枚举类型列表,以便在属性系统中使用。

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()宏声明了作为标志使用的枚举,也就是一起使用OR。另一个宏,Q_CLASSINFO(),允许你附加额外的名称/值对到类的元对象:

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author", "Oscar Peterson")
    Q_CLASSINFO("Status", "Active")

public:
    MyClass(QObject *parent = 0);
    ~MyClass();
};

Qt自己创建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到你的源代码(替换你最喜欢的名字)变量和moc_foo.o或moc_-foo.obj到你的对象变量。

        这两个例子都假设$(DEFINE)和$(INCPATH)展开为define和include传递给c++编译器的路径选项。moc需要这些文件来预处理源文件。

对于实现中的Q_OBJECT类声明(.Cpp)文件,我们建议这样一个makefile规则:

foo.o: foo.moc

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

这保证make会在编译foo之前运行moc.cpp。你可以

#include "foo.moc"

在foo.cpp的末尾,该文件中声明的所有类都是完全已知的。

命令行操作

moc支持的命令行参数如下:

-o<file>将输出写入<file>而不是标准输出。
-f[<file>]强制在输出中生成#include语句。这是扩展名以H或h开头的头文件的默认值。如果你有不遵循标准命名约定的头文件,这个选项很有用。<file>部分是可选的。
-i不要在输出中生成#include语句。这可以用于在包含一个或多个类声明的c++文件上运行moc。对象中的元对象代码应该#include .cpp文件。
-nw不要生成任何警告。(不推荐)。
-p[path]使moc将<path>/前置到生成的#include语句中的文件名。
-I<dir>添加dir到头文件的包含路径。
-E进行预处理;不要生成元对象代码。
-D<macro>[=<def>]定义宏,带有可选的定义。
-U<macro>未定义的宏
-M<key=value>向插件添加额外的元数据。如果一个类指定了Q_PLUGIN_METADATA,键值对将被添加到它的元数据中。这将在运行时为插件解析的Json对象中结束(可从QPluginLoader访问)。这个参数通常用于用构建系统解析的信息来标记静态插件。
@<file>从<file>读取额外的命令行选项。文件的每一行都被视为一个单独的选项。空行将被忽略。注意,选项文件本身不支持这个选项(即一个选项文件不能“包含”另一个文件)。
-h显示选项的使用和列表。
-v显示moc版本号。
-FdirmacOS。将框架目录dir添加到要搜索头文件的目录列表的头。这些目录与-I选项指定的目录交错在一起,并按从左到右的顺序扫描(请参阅gcc的manpage)。通常,使用-F /Library/Frameworks/

可以显式地告诉moc不要解析头文件的部分内容。moc定义了预处理器符号Q MOC_RUN。

#ifndef Q_MOC_RUN
    ...
#endif

moc不能处理c++的所有内容。类模板不能有Q_OBJECT宏

不支持!!!
class SomeTemplate<int> : public QFrame
{
    Q_OBJECT
    ...

signals:
    void mySignal(int);
};

多重继承要求QObject放到第一位置

// 正确
class SomeClass : public QObject, public OtherClass
{
    ...
};
提示:若OtherClass本身就继承自QObject,那么 public QObject就多余了;

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

函数指针不能是信号或槽参数

错误的!!
class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(void (*apply)(List *, void *), char *); // WRONG
};

/********************改进***************************/
正确写法
typedef void (*ApplyFunction)(List *, void *);

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(ApplyFunction, char *);
};

有时用继承和虚函数替换函数指针可能会更好。

枚举和类型defs必须完全限定信号和槽位参数

class MyClass : public QObject
{
    Q_OBJECT

    enum Error {
        ConnectionRefused,
        RemoteHostClosed,
        UnknownError
    };

signals:
    void stateChanged(MyClass::Error error); //MyClass::Error最好不要写成Error
};

嵌套类不能有信号和槽

class A
{
public:
    class B
    {
        Q_OBJECT

    public slots:   // 错误的
        void b();
    };
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值