Qt访问继承类的D-Pointer

Posted

技术标签:

【中文标题】Qt访问继承类的D-Pointer【英文标题】:Qt access D-Pointer of inherited Class 【发布时间】:2014-01-24 15:35:57 【问题描述】:

我试图了解我的整个 d 指针是如何工作的。我得到了大部分零件,但我目前面临一个问题:

就像这里的人 Dpointer inheritance 一样,我想使用 d-pointers 继承一个类(实际上它是 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;

【问题讨论】:

你可以看看其他 Qt 类,看看他们是怎么做的 在 Qt 本身中,这是通过广泛使用需要更改代码的友元类来解决的 @user1723056 要修补 Qt 的 PIMPL 层次结构,您只需要包含私有标头,无需更改代码,但我不鼓励这样做 - 除非您正在编写,否则它真的没有意义一个将被大量实例化的类。 【参考方案1】:

首先,让我们介绍一下基础知识。 IANAL,但它是这样的:

我假设您有一个希望根据 LGPL 条款使用 Qt 的闭源应用程序。

根据美国法律的某些解释,使您的代码依赖于 Qt 的私有标头使其成为 Qt 的派生作品,因此您的代码必须根据 LGPL(或 GPL)条款提供,除非您拥有商业许可。

您在 LGPL 下的义务是让您分发您的应用程序的人能够将其与他们从您有义务提供给他们的源代码编译的 Qt 版本重新链接。这可能是由操作系统完成的动态链接,或使用链接器实用程序完成的静态链接。你是否修改了 Qt 并不重要。他们问,您必须向他们提供 Qt 源代码,其中包含用于构建您在应用中使用的 Qt 的确切构建脚本。

当您依赖私有标头时,有人不可能对您提供的 Qt 版本进行二进制兼容的更改并将其与您的代码重新链接,而不会造成任何问题。可以在不破坏二进制兼容性的情况下更改私有 Qt 类——这就是它们是私有的原因。我自己对 LGPL 的解释如下:如果我的代码能够成功链接并与任何与我随应用程序一起提供的版本二进制兼容的 Qt 版本一起工作,那么我的代码就不是派生工作。当然,这在 Qt 错误和我所做的其他更改的范围内,因此将这个 Qt 修补到旧版本并期望它能够正常运行可能是不可行的。

所以,你唯一能做的就是在 Qt 中修改 QProcess 的 *public 接口来保持你的代码闭源。任何人都可以使用这个修改过的 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) 

【讨论】:

抱歉,如果我误解了您的代码,但您不能使用它来更改 QProcessPrivate 中的变量。你可以吗?这就是我需要做的。 @user1723056 您到底需要做什么以及为什么?【参考方案2】:

可以通过 d_ptr.data() 访问。 我想在不重新编译需要访问 d_ptr 的 Qt 源代码的情况下扩展 QML 的行为。这是我在继承类中获取 QDeclarativeTextEdit 的 d_ptr 中的 QTextDocument 的方法:

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。 例如,这是我在没有继承的情况下在 QDeclaractiveTextEditPrivate 中获取 QTextDocument 的方法:

#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; 

【讨论】:

以上是关于Qt访问继承类的D-Pointer的主要内容,如果未能解决你的问题,请参考以下文章

QT应用开发基础

C ++ QT如何从QMainWindow布局访问QWidget的公共类成员

Python Qt GUI设计入门模板类的单继承和多继承封装

Qt:子窗口中如何获取主窗体ui中的控件

Qt无法从继承类访问*ui指针

Qt继承QTreeWidgetItem的问题