Solved Frage zum Thema private implementation
-
Hallo zusammen,
um in das Thema QtQuick / QML zu kommen, hatte ich mir ein Buch aus dem packt Verlag besorgt. In diesem verwendet der Autor die private implementation Technik mit folgendem Beispiel:private: class Implementation; QScopedPointer<Implementation> implementation;
in der Klassendefinition.
Jetzt habe ich heut noch gelesen, dass es noch eine weitere Methode gibt:
class GeoControllerPrivate; class LIBGEO_EXPORT GeoController : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(GeoController); QScopedPointer<GeoControllerPrivate> const d_ptr; ...
Gibt es denn eine Aussage, welche die richtige Methode ist? Gibt es im Netz eine Doku zu diesem Thema? Warum mache ich denn generell eine private Implementierung?
Danke für Eure Hilfe.
gruss
martin -
Den Qt-Weg erklärt ein Artikel in der Wiki.
Gibt es im Netz eine Doku zu diesem Thema? Warum mache ich denn generell eine private Implementierung?
Du findest sehr viel zu diesem Thema, wenn Du im Netz nach "d-zeiger idiom" oder "pimpl idiom" suchst.
-
Hi, @msauer751
Q_DECLARE_PRIVATE ist wie Q_OBJECT ein Makro. Such mal nach der Deklaraton und versuche sie zu verstehen.
Warum treibt man den Aufwand: Binärkompatibilität.
Wenn du einer Klasse Membervariablen hinzufügst, enfernst oder änderst müssen alle Nutzer neu compiliert werden. Mit PIMPL (pointer to private implementation) kann das vermieden werden.
Grüsse
-
Hi,
danke Euch schonmal für die Infos.
D.h. der Weg über class Implementation ist der allgemeine Weg und bei Verwendung von Qt kann alles einfacher über die Macros gemacht werden?
gruss
martin -
@msauer751 Ja, das kann man so sagen.
Grüsse
-
So,
habe jetzt mal meine Klasse auf Q_DECLARE_PRIVATE / Q_DECLARE_PUBLIC umgestellt. In dem privaten Teil würde ich gern ein Signal mit einem Slot verbinden. In der Public Funktion habe ich dazu das connect aufgerufen:connect(d->qGeoCodeReply, SIGNAL(finished()), this, SLOT(searchDone()));
Allerdings bekomme ich immer die Meldung,
Object::connect: No such slot geo::GeoController::searchDone() in ../../lib-geo/source/controller/geo-controller.cpp:108.
Hier mal mein Code:
include.h:
#ifndef GEO_H #define GEO_H #include <QObject> #include <QGeoServiceProvider> #include <QGeoAddress> #include <QGeoCodeReply> #include <QGeoLocation> #include <QGeoCodingManager> #include <QString> #include <QDebug> #include <QList> #include "lib-geo_global.h" #include "data/geo-point.h" namespace geo { class GeoControllerPrivate; class LIBGEO_EXPORT GeoController : public QObject { Q_OBJECT public: explicit GeoController(QObject *parent = nullptr); ~GeoController(); void setOrt(const QString&); void setHome(const QGeoCoordinate&); void doSearch(void); uint getCnt(void); QList<data::GeoPoint*> getPointList(void); bool Error; protected: QScopedPointer<GeoControllerPrivate> const d_ptr; private: Q_DECLARE_PRIVATE(GeoController); }; } #endif // GEO_H
source.cpp:
#include "controller/geo-controller.h" namespace geo { class GeoControllerPrivate { Q_DISABLE_COPY(GeoControllerPrivate) Q_DECLARE_PUBLIC(GeoController) public: GeoControllerPrivate(GeoController *parent) : q_ptr(parent) , qGeoService("osm") { pQGeoCoder = qGeoService.geocodingManager(); // qDebug() << ">> GeoController > Constructor (" << __LINE__ << ") error " << qGeoService.error() << ", errorstring " << qGeoService.errorString() << ", geocoding " << qGeoService.geocodingFeatures(); if (!pQGeoCoder) { // qDebug() << ">> GeoController > Constructor (" << __LINE__ << ") GeoCodingManager not available!"; Error = true; } } bool doSearch(void) { Error = false; qGeoCodeReply = pQGeoCoder->geocode(qGeoAddress); if (!qGeoCodeReply) { // qDebug() << ">> GeoController > doSearch (" << __LINE__ << ") search failed!"; Error = true; } // else // qDebug() << ">> GeoController > doSearch (" << __LINE__ << ") start search"; return Error; } GeoController *const q_ptr; QGeoServiceProvider qGeoService; QGeoCodingManager *pQGeoCoder{nullptr}; QGeoAddress qGeoAddress; QGeoCodeReply *qGeoCodeReply{nullptr}; QString Ort; uint CntResult; QGeoCoordinate Home; bool Error; QList<data::GeoPoint*> PointList; public slots: void searchDone(void) { QList<QGeoLocation> Loc = qGeoCodeReply->locations(); CntResult = Loc.count(); QGeoCoordinate Temp; data::GeoPoint Point; PointList.clear(); // qDebug() << ">> GeoController > searchDone (" << __LINE__ << ") " << qGeoCodeReply->isFinished(); // qDebug() << ">> GeoController > searchDone (" << __LINE__ << ") " << Loc.count(); for (uint i=0; i < CntResult; ++i) { Temp = Loc.at(i).coordinate(); Point.Clear(); Point.setPoint(Temp); if (Home.isValid()) { Point.setAzimut(Temp.azimuthTo(Home)); Point.setDistance(Temp.distanceTo(Home) / 1000); } PointList.append(&Point); // qDebug() << ">> GeoController > searchDone (" << __LINE__ << ") " << Temp << ", distance = " << Point.getDistance() << ", Azimut = " << Point.getAzimut(); } } }; GeoController::GeoController(QObject *parent) : QObject(parent) , d_ptr(new GeoControllerPrivate(this)) { } GeoController::~GeoController() { } void GeoController::doSearch(void) { Q_D(GeoController); // qDebug() << ">> GeoController > doSearch (" << __LINE__ << ") suche nach Ort = " << d_ptr->Ort; Error = d->doSearch(); connect(d->qGeoCodeReply, SIGNAL(finished()), this, SLOT(searchDone())); } }
Könnte mir einer ein Tip geben, wie ich das mit den Signal / Slot in einer privaten Klasse mache.
Danke schon mal.
gruss
martin -
Ok. Wenn ich in bool doSearch (void) folgendes schreibe
QObject::connect(qGeoCodeReply, &QGeoCodeReply::finished, [=](){searchDone();});
Funktioniert es. Allerdings habe ich keine Ahnung was ich da gemacht habe. (Lambda Funktionen sagen mir nichts).
Habt Ihr eine Erklärung dafür?
gruss
martin -
@msauer751 said in Frage zum Thema private implementation:
Habt Ihr eine Erklärung dafür?
sicher,
in deiner Geo klasse hast du keine deiner Funktionen als SLOT definiert, Qt hat auch hierfür Makros.deswegen die Meldung
Object::connect: No such slot geo::GeoController::searchDone() in ../../lib-geo/source/controller/geo-controller.cpp:108.
searchDone ist nur eine normale Klassenfunktion, aber die alte Qt4 Syntax brauch die Makros.
Die neue Qt5 Syntax braucht diese nicht.
Du bist den extra (und hier unnötigen) Schritt gegangen und hast Qt5Connect Syntax mit einem Lambda verknüpft.Lass es mich für dich vereinfachen:
Object::connect(qGeoCodeReply, &QGeoCodeReply::finished, this, &GeoController::searchDone);
-
Der SLOT befindet sich als public slots (void searchDone(void)) in GeoCodePrivate.
Da GeoCodePrivate nicht von QObject abgeleitet ist, kann ich in der Funktion doSearch auch kein Connect aufrufen. Deswegen habe ich das connect in der Klasse GeoCode mit den Lambda ausdrücken.gruss
martin