moc工具的局限性
moc并不能处理所有的C++特性。我们可以回想上一节的元对象系统及信号和槽的实现机制,这些实现中很少处理C++的重要特性之一——模板,是的moc对模板的支持非常有限,对预编译宏的处理也不够完善。由于信号和槽是基于元对象系统来实现的,moc的局限性也可以看作是信号和槽的局限性,这是我们在使用信号和槽的机制时需要特别注意的。
具体说来,moc或者说信号和槽有如下一些限制:
1. 模板类不能含有信号和槽。比如下面的例子是不支持的:
2. QObject(或其子类)作为多重继承的父类之一时,需要把它放在第一个。
如果你使用多重继承,moc在处理时假设首先继承的类是QObject的一个子类,也就是说,我们需要确保首先继承的类是QObject或其子类。示例如下:
3. 函数指针不能作为信号和槽的参数。下面是一个不符合语法的例子:
对于这种情况,即需要使用函数指针作为信号/槽的参数的情形,一般可以考虑使用继承和虚函数等替代,通常来说使用继承和虚函数是更好的面向对象的实现方法。如果一定需要函数指针的话,也可以使用typedef来满足moc的处理过程,比如下面的用法是能够被moc接受的:
4. enum和typedef变量在作为信号和槽的参数时必须用全名。
由于moc在检查信号和槽的参数时,是逐个字母来比较的,比如Alignment和Qt::Alignment被moc视为不同的参数类型。这个限制主要是Qt 4.0引入命名空间导致修改moc带来的,我们应对的方法是任何时候都在信号和槽的参数中使用全名,比如:
5. 带参数的宏不能被用作信号和槽的参数。
在C/C++中,我们可以用#define来定义带参数的宏,比如:
#define CUBE(x) (x)*(x)*(x)
int n = CUBE(3);
则宏展开的结果就是n=(3)*(3)*(3)
但是在Qt中,moc并不真正展开#define,使用带参数的宏在moc处理的过程中无法被有效的识别,因此不能用来作为信号和槽的参数。下面是一个不合法的例子:
不过不含有参数的宏是可以正常工作的,moc处理的时候把它当作一个普通变量一样就可以了。
6. 嵌套类不能含有信号和槽
moc无法处理嵌套类中的信号和槽,它的实现机制中没有完整的考虑嵌套类的情况。下面是一个错误的例子:
具体说来,moc或者说信号和槽有如下一些限制:
1. 模板类不能含有信号和槽。比如下面的例子是不支持的:
| // 错误的用法 class SomeTemplate<int> : public QFrame { Q_OBJECT ... signals: void bugInMocDetected( int ); }; |
如果你使用多重继承,moc在处理时假设首先继承的类是QObject的一个子类,也就是说,我们需要确保首先继承的类是QObject或其子类。示例如下:
| class SomeClass : public QObject, public OtherClass { ... }; |
| class SomeClass : public QObject { Q_OBJECT ... public slots: // 不合法的 void apply( void (*apply)(List *, void *), char * ); }; |
| typedef void (*ApplyFunctionType)( List *, void * ); class SomeClass : public QObject { Q_OBJECT ... public slots: void apply( ApplyFunctionType, char * ); }; |
由于moc在检查信号和槽的参数时,是逐个字母来比较的,比如Alignment和Qt::Alignment被moc视为不同的参数类型。这个限制主要是Qt 4.0引入命名空间导致修改moc带来的,我们应对的方法是任何时候都在信号和槽的参数中使用全名,比如:
| class MyClass : public QObject { Q_OBJECT enum Error { ConnectionRefused, RemoteHostClosed, UnknownError }; signals: void stateChanged(MyClass::Error error); //Error类型使用全名MyClass::Error }; |
在C/C++中,我们可以用#define来定义带参数的宏,比如:
#define CUBE(x) (x)*(x)*(x)
int n = CUBE(3);
则宏展开的结果就是n=(3)*(3)*(3)
但是在Qt中,moc并不真正展开#define,使用带参数的宏在moc处理的过程中无法被有效的识别,因此不能用来作为信号和槽的参数。下面是一个不合法的例子:
| #ifdef ultrix #define SIGNEDNESS(a) unsigned a #else #define SIGNEDNESS(a) a #endif class Whatever : public QObject { ... signals: void someSignal(SIGNEDNESS(int)); //不合法的参数SIGNEDNESS(int) ... }; |
6. 嵌套类不能含有信号和槽
moc无法处理嵌套类中的信号和槽,它的实现机制中没有完整的考虑嵌套类的情况。下面是一个错误的例子:
| class A { Q_OBJECT public: class B { public slots: // 错误的用法 void b(); ... }; signals: class B { // 错误的用法 void b(); ... }: }; |


