2009-09-10 16 views
22

To pytanie jest już zadawane na tym forum, ale nie rozumiem tej koncepcji.W jaki sposób sygnał i gniazda są zaimplementowane pod maską?

Czytałem i wydaje się, że sygnał i gniazda są zaimplementowane za pomocą wskaźników funkcji, tj. Sygnał jest jedną dużą funkcją, która w środku wywołuje wszystkie podłączone gniazda (wskaźniki funkcji). Czy to jest poprawne? Jaka jest rola wygenerowanych plików mocy w całej historii? Nie rozumiem, jak funkcja sygnału wie, które gniazda mają nazywać, tj. Które gniazda są podłączone do tego sygnału.

Dzięki za poświęcony czas

+0

Nicea pytanie. Zobacz także: http://stackoverflow.com/questions/1413777/how-boost-implements-signals-and-slots – elcuco

Odpowiedz

15

Qt realizuje te rzeczy w sposób, który przypomina interpretowanych języków. To znaczy. konstruuje tablice symboli, które mapują nazwy sygnałów na wskaźniki funkcji, zachowuje je i wyszukuje wskaźnik funkcji według nazwy funkcji tam, gdzie jest to konieczne.

Każdorazowe emitują sygnał, to znaczy pisać

emit something(); 

rzeczywiście wywołać funkcję something(), który automatycznie wygenerowany przez kompilator i meta obiektu umieszczonego w pliku *.moc. W ramach tej funkcji sprawdzane są, do jakich gniazd w danym momencie jest podłączony ten sygnał, a odpowiednie funkcje wrzutowe (które zaimplementowano we własnych źródłach) są kolejno wywoływane za pośrednictwem tablic symboli (w sposób opisany powyżej). I emit, podobnie jak inne słowa kluczowe specyficzne dla Qt, są po prostu odrzucane przez preprocesor C++ po wygenerowaniu *.moc. Rzeczywiście, w jednym z nagłówków Qt (qobjectdefs.h) istnieją takie linie:

#define slots 
#define signals protected 
#define emit 

funkcja Connection (connect) tylko modyfikuje tablice symboli utrzymywana w *.moc pliki, a argumenty przekazywane do niej (z SIGNAL() i ` Makra SLOT) są również wstępnie przetworzone, aby pasowały do ​​tabel.

Oto ogólny pomysł. W swojej innej odpowiedzi ジョージ dostarcza nam linki to trolltech mailing list i another SO question na ten temat.

+4

zasadzie poprawne, można ustawić punkt przerwania na tej emisji i następnie przejść przez proces sygnalizacji. Zazwyczaj dostarczane bezpośrednio, sygnały mogą być w kolejce, jest to konieczne, gdy chcesz połączyć dwa obiekty w różnych wątkach –

5

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?

Powiązane problemy