关于信号和槽,Q_OBJECT
宏在类的声明中添加了一个虚函数qt_metacall()
声明,稍后将由moc
. (它还添加了一些转换声明,但这在这里并不重要。)
然后moc
读取头文件,当它看到宏时,它会生成另一个以虚函数定义.cpp
命名moc_headerfilename.cpp
的文件,并且——你可能会问自己,为什么你可以signals:
在没有正确定义的情况下在头文件中提及 ——信号。
因此,当调用信号时,将执行 mocfile 中的定义,并QMetaObject::activate()
使用信号名称和信号参数调用。然后该activate()
函数确定已建立哪些连接并获取相应插槽的名称。
然后它qt_metacall
使用槽名称和给信号的参数进行调用,元调用函数在一个大的switch
-<code>case 语句的帮助下将其委托给真正的槽。
由于在 C++ 中没有关于信号和槽的实际名称的真正运行时信息,正如已经注意到的,这些将由SIGNAL
和SLOT
宏编码为简单const char*
的 s(将“1”或“2”添加到名称以区分信号和插槽)。
如中所定义qobjectdefs.h
:
#define SLOT(a) "1"#a
#define SIGNAL(a) "2"#a
——</p>
Q_OBJECT
宏所做的另一件事是tr()
在对象中定义可用于翻译应用程序的函数。
编辑
正如你所问的qt_metacast
那样。它检查一个对象是否属于某个类,如果它确实返回指向它的指针。如果不是,则返回 0。
Widget* w = new Widget();
Q_ASSERT(w->qt_metacast("Widget") != 0);
Q_ASSERT(w->qt_metacast("QWidget") != 0);
Q_ASSERT(w->qt_metacast("QObject") != 0);
Q_ASSERT(w->qt_metacast("UnrelatedClass") == 0);
This is needed to provide some runtime reflection which is not possible otherwise. The function is called in QObject::inherits(const char *)
for example and simply checks for inheritance.