Qt access D-Pointer унаследованного класса

Я пытаюсь понять, как работает весь D-указатель. Я получил большинство деталей, но в настоящее время я столкнулся с проблемой:

Как парень здесь Наследование Dpointer я хочу наследовать класс, используя d-указатели (на самом деле это QProcess).

Поскольку функция для доступа к d-указателю является закрытой, я не могу получить к ней доступ с помощью простого наследования. Моя идея состоит в том, чтобы снова использовать макрос Q_DECLARE_PRIVATE, чтобы получить функцию и получить к ней доступ. Может ли это работать? Прежде чем попробовать, я хочу несколько советов, так как я не знаю, может ли это вообще сработать.

(Мне нужно это, чтобы избежать проблем с лицензированием в целом.)

MyProcess.h

#ifndef MYPROCESS_H
#define MYPROCESS_H

class QProcessPrivate;

class MyProcess : public QProcess {
public:
MyProcess(QObject *parent = 0);

protected:
Q_DECLARE_PRIVATE(QProcessPrivate);

};

#endif /* WIDGET_H */

MyProcess.cpp

#include "myprocess.h"
MyProcess::MyProcess(QObject *parent = 0)
: QProcess(parent) {
}

MyProcess::setPid(Q_PID pid) {
Q_D(const QProcess);
d->pid = pid;
}

1

Решение

Прежде всего, давайте рассмотрим основы. IANAL, но здесь это идет:

Я предполагаю, что у вас есть приложение с закрытым исходным кодом, которое желает использовать Qt на условиях LGPL.

Согласно некоторым интерпретациям законодательства США, если ваш код зависит от частных заголовков Qt, он становится производным от Qt, поэтому ваш код должен быть доступен на условиях LGPL (или GPL), если у вас нет коммерческой лицензии.

В соответствии с LGPL вы обязаны предоставить людям возможность распространять ваше приложение, связать его с версией Qt, которую они скомпилировали из источников, которые вы обязаны им предложить. Это может быть динамическое связывание, выполняемое ОС, или статическое связывание, выполняемое утилитой компоновщика. Не имеет значения, изменили ли вы Qt или нет. Они спрашивают, вы должны предоставить им источники Qt с точными сценариями сборки, которые вы использовали для сборки Qt, которую вы используете в своем приложении.

Когда вы зависите от личных заголовков, для кого-то невозможно внести двоичные совместимые изменения в предлагаемую вами версию Qt и связать ее с вашим кодом без каких-либо проблем. Закрытые классы Qt могут быть изменены без нарушения бинарной совместимости, поэтому они являются частными. Сам я интерпретирую LGPL следующим образом: мой код не является производной работой, если он будет успешно связываться и работать с любой версией Qt, которая двоично совместима с версией, которую я предлагаю вместе с моим приложением. Конечно, это в пределах ошибок Qt и других изменений, которые я сделал, так что, возможно, кто-то не сможет исправить этот Qt до более старой версии и ожидать, что он будет работать нормально.

Таким образом, единственное, что вы можете сделать, чтобы ваш код был закрытым, — это изменить * открытый интерфейс QProcess в собственно Qt. Любой желающий может воспользоваться этой модифицированной версией Qt (которую вы предлагаете!), Внести в нее дополнительные бинарно-совместимые изменения и связать ее с вашим кодом. Так что, если вы думаете, что отсутствие модификации Qt и зависимость от частных заголовков облегчит вашу жизнь, ты совсем не в себе.

Вообще говоря, вы не можете наследовать от QXyzPrivate так как вам нужно включить частные заголовки Qt. Так что это не очень хорошая практика, и на самом деле нет веских причин для этого. Цена, которую вы платите, является дополнительным распределением кучи, когда вы создаете экземпляр класса, так что я бы сказал, не беспокойтесь об этом.

Вы должны запустить свою собственную иерархию классов PIMPL. Обратите внимание, что каждый класс, из которого предполагается получить производные, должен предлагать конструктор, ссылающийся на экземпляр закрытого класса.

// myprocess.h

class MyProcessPrivate;
class MyProcess : public QProcess {
Q_DECLARE_PRIVATE(MyProcess) // No semicolon!
public:
explicit MyProcess(int arg, QObject * parent = 0);
~MyProcess();
protected:
MyProcess(MyProcessPrivate&, int arg, QObject * parent); // Must be present to allow derivation
const QScopedPointer<MyProcessPrivate> d_ptr; // Only in the base class, must be protected!
}

// myprocess_p.h

class MyProcessPrivate {
Q_DECLARE_PUBLIC(MyProcess) // No semicolon!
...
public:
explicit MyProcessPrivate(MyProcess*);
protected:
MyProcess * const q_ptr; // Only in the base class, must be protected!
};

// derivedprocess.h

#include "myprocess.h"
class DerivedProcessPrivate;
class DerivedProcess {
Q_DECLARE_PRIVATE(DerivedProcess) // No semicolon!
public:
explicit DerivedProcess(int arg, QObject * parent = 0);
~DerivedProcess();
}

// derivedprocess_p.h

#include "myprocess_p.h"
class DerivedProcessPrivate : public MyProcessPrivate {
Q_DECLARE_PUBLIC(DerivedProcess) // No semicolon!
//...
public:
explicit DerivedProcessPrivate(DerivedProcess*);
};

// myprocess.cpp

MyProcess::MyProcess(int arg, QObject * parent) :
QProcess(parent),
d_ptr(new MyProcessPrivate(this)) {}

MyProcess::MyProcess(MyProcessPrivate & d, int arg) :
d_ptr(&d) {}

MyProcessPrivate::MyProcessPrivate(MyProcess* parent) :
q_ptr(parent) {}

// derivedprocess.cpp

DerivedProcess::DerivedProcess(int arg, QObject * parent) :
MyProcess(* new DerivedProcessPrivate(this), arg, parent) {}

DerivedProcessPrivate::DerivedProcessPrivate(DerivedProcess* parent) :
MyProcessPrivate(parent) {}
4

Другие решения

Доступ к нему можно получить с помощью d_ptr.data ().
Я хочу расширить поведение QML без перекомпиляции исходного кода Qt, которому нужен доступ к d_ptr. Вот как я получаю QTextDocument в d_ptr QDeclarativeTextEdit в наследуемом классе:

QT_FORWARD_DECLARE_CLASS(QDeclarativeTextEditPrivate)
class MyTextEdit : public QDeclarativeTextEdit
{
...
void aMethod()
{
QDeclarativeTextEditPrivate *d = reinterpret_cast<QDeclarativeTextEditPrivate *>(QDeclarativeItem::d_ptr.data());
QTextDocument *d_doc = d->document;
...
}
};

Кстати, мы также можем получить d_ptr без наследования классов.
Например, вот как я получаю QTextDocument в QDeclaractiveTextEditPrivate без наследования:

#include <QtGui/QGraphicsItem>
QT_FORWARD_DECLARE_CLASS(QGraphicsItemPrivate)
class DQGraphicsItem : public QGraphicsItem
{
DQGraphicsItem() {}
public:
QGraphicsItemPrivate *d() const { return d_ptr.data(); }
};

inline QGraphicsItemPrivate *d_qgraphicsitem(const QGraphicsItem *q)
{ return static_cast<const DQGraphicsItem *>(q)->d(); }

#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p.h>
#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h>

inline QDeclarativeTextEditPrivate *d_qdeclarativetextedit(const QDeclarativeTextEdit *q)
{ return static_cast<QDeclarativeTextEditPrivate *>(d_qgraphicsitem(q)); }

inline QTextDocument *d_qdeclarativetextedit_document(const QDeclarativeTextEdit *q)
{ return d_qdeclarativetextedit(q)->document; }
1