d_func, _q_*, Q_DECLARE_PRIVATE
-
Hallo,
ich bin gezwungen mir die QT-Sources anzusehen, da ich eingehende TCP-Datentransfers ausbremsen möchte...
Leider verstehe ich deren Programmierung nicht.
Es wird immer wieder eine d_func() Funktion aufgerufen, deren Definition ich aber nirgends gefunden habe.Außerdem bin ich bei folgendem hängen geblieben:
Q_DECLARE_PRIVATE(QAbstractSocket) Q_DISABLE_COPY(QAbstractSocket) Q_PRIVATE_SLOT(d_func(), void _q_connectToNextAddress()) Q_PRIVATE_SLOT(d_func(), void _q_startConnecting(const QHostInfo &)) Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt()) Q_PRIVATE_SLOT(d_func(), void _q_testConnection())
Was machen Q_DECLARE_PRIVATE, Q_DISABLE_COPY ?
Was ist Q_PRIVATE_SLOT ?
Woher kommen die _q_ Funktionen, die auch nirgends definiert sind?Danke!
-
Q_DECLARE_PRIVATE ist eine abkürzung für das handling von d-pointern.
es erzeugt dir die beiden d_func() und setzt die private klasse als friend-class.
also wird aus Q_DECLARE_PRIVATE(QAbstractSocket):inline QAbstractSocketPrivate* d_func() { return reinterpret_cast<QAbstractSocketPrivate *>(d_ptr); } inline const QAbstractSocketPrivate* d_func() const { return reinterpret_cast<const QAbstractSocketPrivate *>(d_ptr); } friend class QAbstractSocketPrivate;
es ist also nur eine abkürzung für lästige schreibarbeit.
die d_func dient dazu, dass du nicht direkt auf den d_ptr zugreifen musst, dass kann wohl ein bisschen spaß beim vererben vorbeugen.
Q_DISABLE_COPY ist ein abkürzug für das privat setzen des copy-konstruktors und des zuweisungsoperators. spart wieder nur ein bisschen schreibarbeit (diesesmal ist aber parameter der klassennamen).
Q_PRIVATE_SLOT legt ein funktion aus einer privaten klasse als slot für die eigenen klasse fest. will heißen: du kannst nach dem Q_PRIVATE_SLOT(d_func(),void irgendwas());
irgendwas() wie einen normalen slot der klasse benutzen.
also connect(irgendeinObjekt,SIGNAL(signal()),this,SLOT(irgendwas())); benutzen. aus gründen der besseren unterscheidbarkeit werden die immer mit einem _q_ eingeleitet bzw. bei kde mit einem _k_.
-
Hallo!
Danke für deine Antwort, sie hat mir schon sehr weitergeholfen. Ich fasse jetzt erst einmal zusammen was ich denke zu wissen
Also QT erstellt für jede Klasse noch eine "Private" Klasse (die deren Header-Datei auf _p.h endet), die QT-interne Memberfunktionen und -variablen enthält, bei denen sich Trolltech vorbehält diese ohne Ankündigung zu ändern. Die ganzen Präprozessoranweisungen sind also nur dazu da, die Kommunikation zwischen den "Privaten" Klassen und den "Schnittstellenklassen" zu ermöglichen, oder?
Ich habe noch nicht genau kapiert, was der d_ptr eigentlich ist... Ist er vllt. ein Zeiger auf die private Klasse, oder für die private Klasse einer auf die schnittstellenklasse?
Das wäre als erstes mal das wo ich den Fuß in der Tür habe!Ich habe keine Datei gefunden, in der die ganzen Q_DECLARE_PRIVATE, Q_DECLARE_PUBLIC , Q_Q definiert werden gefunden? Wo gibt es so eine Datei, die würde einen großen Teil meiner Fragen selbst beantworten.
Was macht es für einen Sinn einen Kopierkonstruktor und einen Zuweisungsoperator als privates Element einer Klasse zu haben? Prinzipiell würde es doch nur Sinn machen wenn man den Konstruktor auch private setzen würde, damit die Klasse dann nur noch von ihren Friend-Klassen initialisiert werden kann?
In meinem konkreten Fall also, dass die jeweiligen "Privaten" Klassen die dazugehörigen "Public" Klassen als friend definieren und dann jedes "public" Objekt gleich noch ein "private" Objekt miterstellt.Tom
-
fange wir langsam an: ja, trolltech hat das pimpl-idiom in tatsächlich allen klassen von qt durchgezogen, was die garantie der binärstabilität stark erleichtert.
der d-pointer ist einfach nur ein zeiger auf eine instanz der zu dem objekt gehörenden _privaten_ klasse, der von der öffentlichen klasse im ctor angelegt wird und intern dann verwendet wird, um die eigentliche arbeit zu leisten.
der grund für die präzossor-direktiven ist eigentlich auch leicht zu erklären: signal-slot.
man kann nur signals der eigenen klasse emittieren, da diese grundsätzlich und immer protected funktionen sind, was ja auch sehr sinnvoll ist.
wenn man nun aber eine interface- oder proxy-klasse (nichts anderes sind alle öffentlichen klassen in qt) dazwischen packen will, so muss die private klasse, die die eigentliche arbeit macht, irgendwie in die lage versetzt werden, signale zu emittieren.
das erfolgt durch zwei dinge, erstens sie muss mit der öffentlichen klasse befreundet sein, damit sie die privaten funktionen aufrufen kann und sie muss die instanz zu der sie gehört kennen (die öffentliche-instanz wird im q-pointer gespeichert), da signale objekt und nicht klassen bezogen sind.das alles erreicht man mit den beiden makro Q_DECLARE_PUBLIC und Q_DECLARE_PRIVATE. die jeweils drei zeilen code erzeugen, der sich um das ganze kümmert. also jeweils befreunden und die beiden d_func (in der öffentlichen klasse) bzw die beiden q_func (in der privaten klasse) zu erzeugen.
die sache mit den slots wird über die Q_PRIVATE_SLOT-sache geregelt, was schon erklärte.
Q_DISABLE_COPY hat jetzt erstmal nichts mit dem zu tun, worum es vorher ging. das privat setzen des copy-ctors und des zuweisungsoperators dient dazu, dass die klasse nicht kopiert werden kann. das kann sinnvoll sein, wenn es bspw inhaltlich keinen sinn macht.
einfaches bsp: wie kopiert man eine widget das unterfenster hat? will man wirklich, dass bei einer einfachen zuordnung das komplette system mit kopiert wird? oder andere sache: wie kopiert man ein qobject? die frage ist fieser als sie erst scheint, da man auch die signal-slot-verbindungen bedenken muss. ist das eine exakte kopie, wenn das ding hinterher keine der alten verbindungen mehr hat?
oder wie wir hier hatte: wie kopiert man ein QAbstractSocket? den kann man schlicht aus dem grund heraus nicht kopieren, da er abstrakt ist (nicht abstrakt im sinne von c++ aber inhaltlich).Q_DISABLE_COPY, Q_DECLARE_PRIVATE, Q_DEVLARE_PUBLIC, usw stehen in qglobal.h
Q_PRIVATE_SLOT sollte direkt im moc implementiert sein.
-
Noch eine letzte Sache die ich nicht ganz verstehe: friend-Deklarationen vererben sich doch nicht, dann wäre es einer abgeleiteten Klasse also nicht mehr möglich auf die privaten Elemente der QAbstractSocketPrivate Klasse zuzugreifen?
-
das ginge, selbst wenn friend vererbt würde, nicht, da der d-pointer ein privater member ist. der zugriff darauf ist für kinder eh nicht möglich.
ein kind muss halt das öffentliche interface der klasse nutzen, um auf die member der elternklasse zuzugreifen. ob das ein nachteil oder vorteil ist, ist so generell nicht zu beantworten.