I think I should add the following.
There is another linked question -- and there is a very good article that can be considered as a quite detailed expansion to it's answer; here is this article again, with improved (though still not perfect) code syntax highlighting.
Here's my short retelling of it, that may be prone to mistakes )
Basically when we insert the Q_OBJECT
macro in our class definition, the preprocessor expands it to a static QMetaObject
instance declaration, one that would be shared by all instances of the same class:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
This instance, in turn, on initialization will store the signatures ("methodname(argtype1,argtype2)"
) of the signals and the slots, what will allow to implement the indexOfMethod()
call, which returns, well, method's index by it's signature string :
struct Q_CORE_EXPORT QMetaObject
{
// ... skip ...
int indexOfMethod(const char *method) const;
// ... skip ...
static void activate(QObject *sender, int signal_index, void **argv);
// ... skip ...
struct { // private data
const QMetaObject *superdata; // links to the parent class, I guess
const char *stringdata; // basically, "string1\0string2\0..." that contains signatures and other names
const uint *data; // the indices for the strings in stringdata and other stuff (e.g. flags)
// skip
} d;
};
Now when the moc
creates the moc_headername.cpp
file for the Qt class header headername.h
, it puts there the signature strings and other data that are necessary for correct initialization of the d
structure, and then writes the initialization code for the staticMetaObject
singleton using this data.
Another important thing it does is generation of the code for the object's qt_metacall()
method, that takes an object's method id and an array of argument pointers and calls the method via a long switch
like this:
int ClassName::qt_metacall(..., int _id, void **_args)
{
// ... skip ...
switch (_id) {
case 0: signalOrSlotMethod1(_args[1], _args[2]); break; // for a method with two args
case 1: signalOrSlotMethod2(_args[1]); break; // for a method with a single argument
// ... etc ...
}
// ... skip ...
}
Last, for every signal moc
generates an implementation, which contains a QMetaObject::activate()
call :
void ClassName::signalName(argtype1 arg1, argtype2 arg2, /* ... */)
{
void *_args[] = { 0, // this entry stands for the return value
&arg1, // actually, there's a (void*) type conversion
&arg2, // in the C++ style
// ...
};
QMetaObject::activate( this,
&staticMetaObject,
0, /* this is the signal index in the qt_metacall() map, I suppose */
_args
);
}
Finally, the connect()
call translates the string method signatures to their integer ids (the ones used by qt_metacall()
) and maintains a list of signal-to-slot connections; when the signal is emitted, the activate()
code goes through this list and calls the appropriate object "slots" via their qt_metacall()
method.
To sum up, the static QMetaObject
instance stores the "meta-information" (method signature strings etc), a generated qt_metacall()
method provides "a method table" that allows any signal/slot to be called by an index, signal implementations generated by moc
use these indexes via activate()
, and finally connect()
does the job of maintaining a list of signal-to-slot index maps.
*Note: there's a complication of this scheme used for the case when we want to deliver signals between different threads ( I suspect that one has to look at the blocking_activate()
code ), but I hope the general idea remains the same )
This is my very rough understanding of the linked article, which easily may be wrong, so I do recommend to go and read it directly )
PS. As I'd like to improve my understanding of Qt implementation -- please let me know of any inconsistencies in my retelling !
Since my other (earlier) answer was deleted by some zealous editor, I will append the text here ( I am missing few details that were not incorporated in Pavel Shved's post, and I doubt the person who deleted the answer cared. )
@Pavel Shved:
I am pretty sure that somewhere in Qt headers there exists a line:
#define emit
Just to confirm: found it in old Qt code by Google Code Search. It is quite likely that it is still there ) ; the found location path was :
ftp://ftp.slackware-brasil.com.br›
slackware-7.1›
contrib›
kde-1.90›
qt-2.1.1.tgz›
usr›
lib›
qt-2.1.1›
src›
kernel›
qobjectdefs.h
Another complementory link: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html -- see the answer by Andreas Pakulat
And here is another piece of the answer : Qt question: How do signals and slots work?