Seite 1 von 1

[gelöst] Erben von privaten Qt Klassen (PIMPL)

Verfasst: 16. Dezember 2009 14:17
von abelmi
Hallo zusammen,
ich habe meine eigene Implementierung der Klasse QSqlTableModel sowie QSqlTableModelPrivate (Klasse MySqlTableModel und MySqlTableModelPrivate).
MySqlTableModel erbt von QSqlQueryModel; MySqlTableModelPrivate erbst von QSqlQueryModelPrivate.

Diese und weitere Klassen habe ich in eine Bibliothek zusammengefasst. Wenn ich diese Bibliothek dynamisch übersetze (als auch Qt dynamisch), erhalte ich folgenden Linkerfehler:

Code: Alles auswählen

2>MySqlTableModel.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall QSqlQueryModelPrivate::~QSqlQueryModelPrivate(void)" (??1QSqlQueryModelPrivate@@UAE@XZ) referenced in function __unwindfunclet$??0MySqlTableModelPrivate@@QAE@XZ$0
2>MySqlTableModel.obj : error LNK2019: unresolved external symbol "public: void __thiscall QSqlQueryModelPrivate::initColOffsets(int)" (?initColOffsets@QSqlQueryModelPrivate@@QAEXH@Z) referenced in function "public: virtual void __thiscall MySqlTableModel::setTable(class QString const &)" (?setTable@MySqlTableModel@@UAEXABVQString@@@Z)
Wenn ich mein Projekt statisch übersetze (als auch Qt statisch), funktioniert alles problemlos.

Hier ein Ausschnitt aus meinem Code:

Global.h mit Definition und Makros

Code: Alles auswählen

...
#ifdef BUILD_DLL 
   #define EXPORT __declspec(dllexport) 
#else 
   #define EXPORT __declspec(dllimport) 
#endif
...

MySqlTableModel.h

Code: Alles auswählen

...
class EXPORT MySqlTableModel: public QSqlQueryModel
{
// enable qt signals/slots
private:
    Q_OBJECT
    Q_DECLARE_PRIVATE(MySqlTableModel)
public:
...

MySqlTableModel_p.h

Code: Alles auswählen

...
class MySqlTableModelPrivate: public QSqlQueryModelPrivate
{
    Q_DECLARE_PUBLIC(MySqlTableModel)

public:
Habt ihr eine Idee, wie ich dieses Problem lösen kann?

Verfasst: 16. Dezember 2009 16:48
von Christian81
Linkst Du auch gegen QtSql ?

Verfasst: 17. Dezember 2009 11:00
von abelmi
Wenn ich meine Bibliothek als Debug Version dynamisch übersetzte, dann linke ich unter anderem auch gegen Sqld4.lib.

Wenn Wenn ich meine Bibliothek statisch übersetzte, dann wird gegen QtSqld.lib gelinkt.

Für die Release Version respektive jeweils ohne das "d" im Namen.

Die statische Version funktioniert problemlos, während die dynamische Version die oben genannten Linkerfehler verursacht. Ich denke, es hat was irgendetwas mit dem __declspec(dllexport) zu tun.

Verfasst: 17. Dezember 2009 11:04
von Christian81
QSqlQueryModelPrivate ist in QSql4(d).lib definiert.

Verfasst: 17. Dezember 2009 11:20
von franzf
Christian81 hat geschrieben:QSqlQueryModelPrivate ist in QSql4(d).lib definiert.
Werden die Symbole auch exportiert?

Im allgemeinen sollte man aber auf die Verwendung von den ganzen private-Klassen verzichten. Du hast keinen Zugriff auf den Header und musst den eh schon rüberkopieren. Dann geh doch gleich her und kopier dir die Sourcen auch mit und modifizier diese direkt.
QSqlTableModel wird intern weiterhin die QSqlTableModePrivate nutzen und nicht deine - außer du holst dir auch noch den QSqlTableModel-Header in dein Projekt und modifizierst den, damit du den pimpl-Pointer selber setzen kannst.

Kannst du mal erklären, warum du unbedingt den private-Kram auch noch modifizieren musst? Warum kannst du nicht einfach nur von QSqlTableModel ableiten?

Verfasst: 17. Dezember 2009 11:26
von Christian81
@franzf: Du hast Recht - QSqlQueryModelPrivate wird nicht exportiert. Warum sollte es auch... :)

Statisch geht es angeblich nur da beim statischen bauen kein Linker angeworfen wird. Wenn später die statische Lib gegen ein Executable gelinkt wird kommt der gleiche Fehler.

Verfasst: 17. Dezember 2009 12:21
von abelmi
@franzf: Meine eigene Implementierung der QSqlTableModel (Klasse: MySqlTableModel) ist eine veränderte Kopie der orginal Qt Klasse, um das ursprüngliche Verhalten anzupassen.
Auch die QSqlTableModelPrivate Klasse habe ich kopiert und angepasst. Diese verwendet aber auch Methoden der Basisklasse QSqlQueryModel.

Ich müsste jetzt wohl auch die QSqlQueryModelPrivate Klasse sowie deren Basisklassen, bis hoch zur QObjectPrivate Klasse kopieren, was meiner Meinung unsinnig wäre.

Verfasst: 17. Dezember 2009 12:24
von abelmi
@Christian81: ja genau. Bei der QSqlQueryModelPrivate fehlt der DLL Export.

Die statische Lib konnte ich problemlos gegen das Executable linken. Das hat schon in allen meiner Projekten problemlos funktioniert. Ich vermute stark, dass in statsichen Bibliotheken alle Symbole öffentlich sind.

Edit:
Ich verwende ein statisch übersetztes Qt. Daher kommt es beim Linken meiner statischen Lib auch nicht zu einem Linkerfehler. Wenn Qt dynamisch übersetzt wäre, denke ich würde es auch zu einem Fehler kommen wie du geschrieben hast.

Verfasst: 18. Dezember 2009 14:16
von abelmi
Ich habe nun selbst eine Lösung für mein Problem gefunden.
Ich habe die Klasse QSqlQueryModelPrivate nun veröffentlicht, indem ich in die Deklaration der Klasse das Makro Q_SQL_EXPORT hinzugefügt und Qt neu übersetzt habe.

Code: Alles auswählen

...
class Q_SQL_EXPORT QSqlQueryModelPrivate: public QAbstractItemModelPrivate
{
...
Nun scheint alles problemlos zu funktionieren.

Verfasst: 18. Dezember 2009 14:21
von Christian81
Qt verändern ist nicht wirklich sinnvoll - dann geht es nur mit dieser speziellen Version.
Deshalb zurück zur ersten Frage - warum brauchst du überhaupt Zugriff auf Daten von QSqlQueryModelPrivate??