2010-01-05 6 views
15

Kann mir jemand die Grundidee von Qt-Signalen erklären & slots mechanism IMPLEMENTATION? Ich möchte wissen, was all diese Q_OBJECT-Makros "in C++" machen. Diese Frage ist nicht über Signale & Slots Nutzung.Wie implementiert Qt Signale und Steckplätze?

hinzugefügt: Ich weiß, dass Qt MoC-Compiler verwendet, um Qt-C++ in Plain C++ zu transformieren. Aber was macht Moc? Ich habe versucht, „moc_filename.cpp“ Dateien zu lesen, aber ich habe keine Ahnung, was so etwas wie

void *Widget::qt_metacast(const char *_clname) 
{ 
if (!_clname) return 0; 
if (!strcmp(_clname, qt_meta_stringdata_Widget)) 
    return static_cast<void*>(const_cast< Widget*>(this)); 
return QDialog::qt_metacast(_clname); 
} 
+0

dup: http://stackoverflow.com/questions/1406940/how-signal-und-slots-are-implemented-under-the-hood – elcuco

Antwort

16

Bezüglich der Signale und Steckplätze fügt das Makro Q_OBJECT eine virtuelle Funktion qt_metacall() Deklaration in die Deklaration der Klasse ein, die später durch die moc definiert werden soll. (Es fügt auch einige Erklärungen für die Konvertierung, aber das ist nicht so wichtig hier.)

Die moc liest dann die Header-Datei und wenn es das Makro sieht, erzeugt er eine andere .cpp Datei moc_headerfilename.cpp mit den Definitionen auf die virtuellen Funktionen benannt und - Sie haben sich vielleicht gefragt, warum Sie mit der Erwähnung der signals: in Ihrer Header-Datei ohne eine ordnungsgemäße Definition - der Signale.

Wenn also ein Signal aufgerufen wird, wird die Definition aus der Mocfile ausgeführt und QMetaObject::activate() wird mit dem Namen des Signals und den Argumenten des Signals aufgerufen. Die Funktion activate() ermittelt dann, welche Verbindungen hergestellt wurden, und ruft die Namen für die entsprechenden Steckplätze ab.

Dann ruft es qt_metacall mit den Schlitznamen und die auf das Signal gegeben Argumenten und die metacall Funktion delegiert dies mit Hilfe einer großen switch-case Aussage zu den realen Slots.

Da es keine wirklichen Laufzeitinformationen möglich in C++ über die tatsächlichen Namen für die Signale und Slots, wie bereits bemerkt worden ist, wird diese durch die SIGNAL und SLOT Makros auf einfache const char* s codiert werden (entweder mit „1“ oder "2" hinzugefügt, um Signale von den Steckplätzen zu unterscheiden.

Wie definiert in qobjectdefs.h:

#define SLOT(a)  "1"#a 
#define SIGNAL(a) "2"#a 

-

Die andere Sache, die Q_OBJECT Makro tut, ist die Definition der tr() Funktionen in Ihrem Objekt, das verwendet werden kann, Ihre Anwendung zu übersetzen.

Bearbeiten Als Sie gefragt, was die qt_metacast tut. Es prüft, ob ein Objekt zu einer bestimmten Klasse gehört und ob es den Zeiger darauf zurückgibt. Ist dies nicht der Fall, wird 0 zurückgegeben.

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); 

Dies ist erforderlich, um eine Laufzeitreflexion zu ermöglichen, die andernfalls nicht möglich ist. Die Funktion wird beispielsweise in QObject::inherits(const char *) aufgerufen und prüft einfach auf Vererbung.

+1

Weitere Informationen finden Sie auch in diesem Blogbeitrag: http://woboq.com/blog/how-qt-signals-slots-work.html – guruz

3

Diese Makros „einfach in C++“ absolut nichts tun, bedeutet, - sie erweitern Strings zu leeren (glaube ich) .

QT verwendet einen Meta-Objekt-Compiler, der C++ - Code für Q_OBJECT-fähige Klassen generiert (implementiert unter anderem die von Ihnen definierten Signale/Slots).

Sie können mehr darüber in der official documentation lesen.

+0

In der Tat. Wenn Sie den Code kompilieren, können Sie sich die erzeugte Quelle ansehen. –

+1

Signale und Slots müssen einen kleinen Unterschied haben, wenn sie erweitert werden, da Sie 'connect()' Signal an Signal senden können und dann wäre es nicht klar, wofür die Zeichenfolge steht. – Debilski

-1

Die Grundidee ist, dass Sie Ihre Objekte verbinden können, so dass sie eine Methode (Slot) ausführen können, wenn ein Signal ausgeführt wird.

connect(pistol,SIGNAL(sigShoot()),runner,SLOT(slotRun())) 

Bei der obigen Verbindung, wenn die Pistole das Signal ausgibt, wird der Läufer seinen Schlitz ausführen.

Dazu müssen Sie Ihre Signale und Steckplätze in Ihren jeweiligen Klassen deklarieren.

ist die Grundidee.

Viel Glück!

+5

Aber das OP fragte nach der internen Implementierung und nicht nach der Art der Verwendung. –

+0

Die Idee sieht aus, wie Dojo mit Nachrichtensystem umgeht. –