Myślę, że powinienem dodać następujące.
Istnieje another linked question - i istnieje a very good article, które można uznać za dość szczegółowe rozwinięcie jego answer; here is this article again, z poprawionym (choć wciąż niedoskonałym) podświetlaniem składni kodu.
Oto moja krótka opowieść o tym, że mogą być podatne na błędy)
Zasadniczo kiedy wstawić Q_OBJECT
makro w naszej definicji klasy, preprocesor rozszerza go do statycznego deklaracji QMetaObject
przykład taki, który będzie wspólną przez wszystkich wystąpień tej samej klasy:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
Ta instancja z kolei na inicjalizacji będzie przechowywać podpisów ("methodname(argtype1,argtype2)"
) sygnałów i slotów, co pozwoli wdrożyć indexOfMethod()
połączeń, który zwraca, dobrze, metodę wskaźnika poprzez swojego sygnatura:
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;
};
Teraz gdy moc
tworzy plik moc_headername.cpp
dla klasy nagłówku Qt headername.h
, stawia tam ciągi podpis i inne dane, które są niezbędne dla poprawna inicjalizacja struktury d
, a następnie zapisuje kod inicjujący dla singletonu staticMetaObject
przy użyciu tych danych.
Kolejną ważną rzeczą robi jest generowanie kodu dla qt_metacall()
metody obiektu, który zabierze metody identyfikator obiektu, oraz tablicę wskaźników argumentów i wywołuje metodę poprzez długi switch
jak ten:
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 ...
}
Ostatnio, na każdy sygnał moc
generuje implementację, która zawiera QMetaObject::activate()
połączenia:
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
);
}
Wreszcie rozmowa connect()
tłumaczy stri ng podpisy metod do ich liczb całkowitych (te używane przez qt_metacall()
) i utrzymuje listę połączeń sygnał-gniazdo; kiedy sygnał jest emitowany, kod activate()
przechodzi przez tę listę i wywołuje odpowiedni obiekt "szczeliny" za pomocą ich metody qt_metacall()
. Podsumowując, statyczna instancja przechowuje "meta-informacje" (łańcuchy znaków metod itp.), Wygenerowana metoda qt_metacall()
zapewnia "tabelę metod", która pozwala na wywołanie dowolnego sygnału/szczeliny przez indeks, sygnał implementacje generowane przez moc
używają tych indeksów za pośrednictwem activate()
, a wreszcie connect()
zajmuje się utrzymywaniem listy map indeksu sygnału do gniazda.
* Uwaga: nie jest to powikłanie tego schematu stosowanego do przypadku, gdy chcemy dostarczać sygnały od różnych wątków (podejrzewam, że trzeba spojrzeć na kod blocking_activate()
), ale mam nadzieję, że ogólna idea pozostaje taka sama)
to jest mój bardzo szorstki zrozumienie związanego artykułu, który łatwo może być nie tak, więc jest zalecane, aby przejść bezpośrednio i ją przeczytać)
PS. Chciałbym lepiej zrozumieć implementację Qt - daj mi znać o wszelkich niespójnościach w moim opowiadaniu!
Ponieważ mój drugi (wcześniej) Odpowiedź została usunięta przez jakiś gorliwy edytorze, będę dołączać tekst tutaj (brakuje mi kilka szczegółów, które były nie włączone postu Paweł Szwed, a wątpię osobę usunięto odpowiedź pod opieką.)
@Pavel Shved:
Jestem pewien, że gdzieś w Qt nagłówków istnieje wiersz:
#define emit
Wystarczy potwierdzić: znaleziono go w starego kodu Qt przez Google Code Search. Jest całkiem prawdopodobne, że wciąż tam jest); znaleziony ścieżka lokalizacja była:
ftp://ftp.slackware-brasil.com.br> slackware-7,1> contrib> kde- 1,90> QT 2.1.1.tgz> usr> Ilb> qt-2.1.1> źródło> jądro > qobjectdefs.h
Innym complementory Link: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html - patrz odpowiedź przez Andreas Pakulat
I tu jest kolejny kawałek odpowiedź: Qt question: How do signals and slots work?
Nicea pytanie. Zobacz także: http://stackoverflow.com/questions/1413777/how-boost-implements-signals-and-slots – elcuco