Linux 版 (精华区)

发信人: tcpip (高级草包), 信区: Linux
标  题: Qt Documentation------使用元对象编译器(Use MOC)
发信站: 哈工大紫丁香 (2000年06月11日12:53:18 星期天), 转信


使用元对象编译器 


翻译:seasky

在诸多的工具中,MOC是用来处理QT中C++扩展 的应用程序. 

MOC读取类的声明并构造这个类的包括所有single和slots的C++源文件 (甚至还要多一点 
).
Moc输出的C++源文件必须能被编译而且和类的执行 
代码连接(或者能被包括---#included 进源文件中). 

在Qt指南的第七章介绍了如何使用Moc. 第七上包括一个使用了signals和slots的源 
代码简单的例子: 使用
moc来进行编译 

调用 moc 

下面是moc支持的命令行选项: 

-o file 
输出重定向到一个文件(file) 而不是基本输出(stdout). 
-f 
强制在输出中生成#include语句. 这对符合正则表达式(\.[hH][^.]*) 的文件来说 
是缺省得设置.
(另外,文件的扩展名以H 或 h开始). 
这个选项只对你的不符合基本命名规则的头文件有用. 
-i 
不在输出中生成#include语句.这个选项也许在moc处理
包括一个或多个类声明的C++文件时才用到.这适应得在.cpp文件中包括 
(#include)这个元对象的代码.如果
-i 和 -f 都被设置了, 则后一个起作用. 
-nw 
不生成任何警告. Discouraged. 
-ldbg 
向基本输出stdout输出所有的debug信息. 
-dbg 
在内部调试时把所有的非信号(non-signal)成员都当作slots. 这对于编制Qt客 
户短程序是不是很有用. 
-p path 
在生成的#include声明的文件名前加上路径 (path/) (如果有的话). 
-q path 
在生成的qt #include文件名前加上路径. 

用法: 

moc 几乎总是被 make(1)调用, 而不是手工. 

moc 典型的用法是处理一个包括有如下框架的输入文件: 

class YourClass : public QObject {
Q_OBJECT
public:
YourClass( QObject * parent=0,
const char * name=0 );
~YourClass();

signals:

public slots:

};

如果你只使用GNU make的话,下面是一个有用的原则: 

m%.cpp: %.h
moc $< -o $@

如果你要编写可移植的代码的话, 你可以使用下面的个别的规则: 

mNAME.cpp: NAME.h
moc $< -o $@

必须记住需要向SOURCES (来代替你的喜欢的名字) 变量中添加>mNAME.cpp 和向OBJECTS
变量中添加mNAME.o 

(比如我们喜欢为我们的C++ 源文件命名为 .cpp文件, 尽管moc并不知道,当然你也可以 
使用 .C, .cc, .CC,.cxx
后缀,如果你喜欢甚至可以用c++作后缀 .) 

如果你在C++文件中声明了类的话,建议你使用如下的规则: 

NAME.o: mNAME.cpp

mNAME.cpp: NAME.cpp
moc -i $< -o $@

这能够保证make(1) 在编译 NAME.cpp 之前先运行moc. 你可以在NAME.cpp 后面敲入 

#include "nNAME.cpp"

这样的话在该文件中的所有的类声明就全知道了. 

诊断: 

有些时候你可能被告知连接错误,说你的 YourClass::className() 没有被
定义或是你的类缺少vtbl.这种错误在你忘记了编译moc生成的C++源文
件或是没有把目标object文件包括在连接命令里的时候会经常发生 . 

moc 会对你提出一些危险或不合法的警告. 

Bugs

moc 并不扩展 #include 或 #define, 她只是简单的直接跳过遇到的预处理指令. 尽管 
这很可惜, 但通常在实
践中并不是一个问题. 

moc 也不对所有的 C++进行处理. 这主要的问题是类的模板没有包括signals 或 
slots. 这是个严重的问题.
例子如下: 

class SomeTemplate : public QFrame {
Q_OBJECT
[...]
signals:
void bugInMocDetected( int );
};

不很重要的是,这些结构是非法的. 所有的结构都有自己的工作区,这是一个比较好的选
择,所以修复这个bugs倒不是我们最紧要的任务. 

多重继承需要以QObject 开始

如果你用到了多重继承, moc 假设你的第一个被继承类应该是 QObject的一个子孙. 同 
样,
也要保证只有第一个被继承的类是QObject. 

class SomeClass : public QObject, public OtherClass {
[...]
};

这个bug同样是不可修复的; 因为moc 并不展开 #include 或 #define, 她并不找出那 
一个基础类是QObject. 

函数的指针不能作为signals 或 slots的参数

在很多情况下,你可能认为继承是一种比较好的选择. 下面是一个语法有错的例子: 

class someClass : public QObject {
Q_OBJECT
[...]
public slots:
void apply(void (*applyFunction)(QList*, void*), char*);
};

你也可以这样写: 

typedef void (*ApplyFunctionType)(QList*, void*);

class someClass : public QObject {
Q_OBJECT
[...]
public slots:
void apply( ApplyFunctionType, char *);
};

(有时通过继承和虚汗数替换函数的指针甚至要更好,signals or slots.) 

友元的定义不能被放在signals 和 slots 段里 

通常情况下,不要在signals和slots段里放置友元的定义,尽管有些时候是好用的. 
而应把他们放在private,protected
或 public 段里. 这里是表达错误的例子: 

class someClass : public QObject {
Q_OBJECT
[...]
signals:
friend class ClassTemplate;
};

Signals 和 slots 是不能被升级的 

在 C++ 里, 把一个继承的成员函数升级为 public 状态还没有包括 signals 和 
slots. 这里有个不合法的例子: 

class Whatever : public QButtonGroup {
[...]
public slots:
void QButtonGroup::buttonPressed;
[...]
};

The QButtonGroup::buttonPressed() slot is protected. 

C++ 测试: 当你要把一个保护类型的成员函数升级了的话,会发生什么? 
那个函数会被冲在? 

1.#所有的都被重载. 
2.#在C++里是非法的. 

典型的宏不能被用作signal 和 slot 的参数

因为 moc 不扩展 #define, 带有参数的典型的宏在signals 或 slots里是不好用的. 
这里有个不合法的例子: 

#ifdef ultrix
#define SIGNEDNESS(a) unsigned a
#else
#define SIGNEDNESS(a) a
#endif

class Whatever : public QObject {
[...]
signals:
void someSignal( SIGNEDNESS(a) );
[...]
};

一个没有参数的 #define 是好用的. 

嵌套的类不能放在signals 和 slots 段里也不能拥有 signals 和 slots 

例子如下: 

class A {
Q_OBJECT
public:
class B {
public slots:
void b(); // Nested class with slot
[....]
};
signals:
class B {
void b(); // Nested class in signals:

[....]
}:
};

构造函数不恩能够在 signals 或slots 段里使用

为什么不能够在signals和slots段里放置构造函数,对于我来说始终是个谜. 尽管有些
时候好用,你也无论如何不能那样做. 把他们放在他们应该呆的private, protected 或 
public 段里. 例子如下: 

class SomeClass : public QObject {
Q_OBJECT
public slots:
SomeClass( QObject *parent, const char *name )
: QObject( parent, name ) {}
[...]
};

Signals 和 slots 不能有缺省得参数 

因为 signal->slot 的绑定在运行的时候出现, 所以在理论上说使用缺省的参数---编 
译试的情况----是很困难的.
这里有个错误的例子: 

class SomeClass : public QObject {
Q_OBJECT
public slots:
void someSlot(int x=100);
};

Signals 和 slots 不能有模式化的参数

尽管moc会接受这种情况,但是声明拥有模式化(template-type)参数的 signals 和 
slots 还是不能够正常的工作.
向下面的例子,把signal 连接到 slot 上去的话, 当signal启动的时候, 
slot见不会工作: 

[...]
public slots:
void MyWidget::setLocation (pair location);

[...]
public signals:
void MyObject::moved (pair location);

然而, 你可以通过明确的声明参数的类型来解决这个限制, 就像这样: 

typedef pair IntPair; 
[...]
public slots:
void MyWidget::setLocation (IntPair location);

[...]
public signals:
void MyObject::moved (IntPair location);

这样就会正常工作了. 


Copyright ?1999 Troll Tech
Trademarks 
Qt version 1.44

 -- 
"这一千多年没写诗了?" 
"写了, 不过只写了两句." "千年得两句, 一定是万古丽句了. 念来听听."
"好吧, 我现丑了" 太白星清了清嗓子, 浑厚的男中音在天庭响起:大海啊, 都是水;
骏马啊, 四条腿;

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: tcpip.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.827毫秒