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毫秒