两个宏的释义?作用?实现?用法?
作用
Q_DECLARE_PRIVATE是为了实现QT内部的Q指针和D指针功能的宏定义,通过Q/D指针来保证程序的二进制兼容。
什么是二进制兼容?
简单的来说,就是随着lib/dll库的更新迭代,调用库文件的程序在不需要重编译的情况下仍能够正常使用,以达到"兼容"二进制库文件的变化,这就叫做二进制兼容。对应二进制兼容的还有源代码兼容:就是需要对程序重新编译才能使用新的库文件。
Q/D指针只是Qt实现二进制兼容的一种方法,简单的来说就是将功能通过指针对象私有化,隐藏起来具体的细节。比如对于一个InfterfaceClass, 它所提供的所有接口都是通过一个InfterfaceClassPrivate objectPoint来具体操作的,InfterfaceClassPrivate代表插件或者库,库无论如何变化都不会影响到objectPoint的指针在内存中存放的顺序和位置。
class InfterfaceClass
{
public:
InfterfaceClass();
~InfterfaceClass();
int getNumber() const
{
return m_d->getNumber();
}
void setNumber(int number)
{
m_d->setNumber(number);
}
private:
InfterfaceClassPrivate* m_d;
}
实现二进制兼容的方法有很多,我们中先重点了解Q/D指针的原理。
Q/D指针的原理
d指针指向封装的私有类,q指针指向公共的类。通过继承转换,将private指针强转(reinterpret_cast<>)为对应的子类private指针对象。
自定义实现Q/D指针的类:借助PImpl(private implementation, 从代码实现角度上说也可以叫point to implementation,是一种简单的桥接模式)机制
注意:使用Q/D指针宏时需要在.pro中添加core-private
实现和使用Q/D指针
考虑到多重继承,所以被继承的最root base class(非private class)才会有一个private object pointer,借助于reinterpret_cast强转函数完成类型转换
为什么要在origion base class中才会拥有private object pointer?而不是在每一个inherit class 中都创建这样一个成员变量?因为多重继承下,在构造函数中会将每一个继承下来private class 都构造一遍
//widget.h
class Widget
{
public:
Widget();
protected:
Widget(WidgetPrivate& d); //allow subclass access the method
WidgetPrivate* d_ptr;
}
//widget.cpp
Widget::Widget():d_ptr(new WidgetPrivate(this))
{
}
Widget::Widget(WidgetPrivate& d): d_ptr(&d)
{
}
/******************* splite line **************************/
//widget_p.h
struct WidgetPrivate
{
WidgetPrivate(Widget* q): q_ptr(q){}
Widget* q_ptr;
Rect geometry;
String styleString;
}
/******************* splite line **************************/
//label.h
class Label: public Widget
{
Q_DECLARE_PRIVATE(Label)
public:
Label();
void setText(const QString& text);
protected:
Label(LabelPrivate& d);
}
//label.cpp
#include "widget_p.h"
class LabelPrivate: WidgetPrivate
{
public:
String text;
}
//initialize the d-pointer with our own Private
Label::Label():Widget(*new LabelPrivate)
{
}
Label:Label(LabelPrivate& d): Widget(d)
{
}
//with Q_D you can use the numbers od LabelPrivate form Label
void Label::setText(const QString& text)
{
Q_D(Label);
d->text = text;
}
//with Q_Q you can use the numbers of Label from LabelPrivate
void LabelPrivate::someHelpFunction()
{
Q_Q(Label);
q->selectAll();
}
另一个参考实现:
//lineedit.h
#ifndef LINEEDIT_H
#define LINEEDIT_H
#include <QLineEdit>
class LineEditPrivate;
class LineEdit:public QLineEdit
{
Q_OBJECT
public:
explicit LineEdit(QWidget *parent=nullptr);
virtual ~LineEdit();
void setTipText(const QString &text);
signals:
void verificationResult(bool,QString);
protected:
LineEdit(LineEditPrivate &d,QWidget *parent=nullptr);
LineEditPrivate * d_ptr;
private:
Q_DECLARE_PRIVATE(LineEdit)
};
#endif // LINEEDIT_H
//lineedit.cpp
#include "lineedit.h"
#include "lineedit_p.h"
LineEdit::LineEdit(QWidget *parent):
QLineEdit(parent),
d_ptr(new LineEditPrivate(this))
{
}
LineEdit::~LineEdit()
{
Q_D(LineEdit);
delete d;
}
void LineEdit::setTipText(const QString &text)
{
Q_D(LineEdit);
d->tipText = text;
}
LineEdit::LineEdit(LineEditPrivate &d, QWidget *parent):
d_ptr(&d),
QLineEdit(parent)
{
}
lineeditprivate的实现
#ifndef LINEEDIT_P_H
#define LINEEDIT_P_H
#include <QObject>
class LineEdit;
class LineEditPrivate{
Q_DECLARE_PUBLIC(LineEdit)
public:
LineEditPrivate(){}
~LineEditPrivate(){}
LineEditPrivate(LineEdit *parent):
q_ptr(parent){}
//data
QString tipText;
QRegExp regExp;
protected:
LineEdit * q_ptr;
};
#endif // LINEEDIT_P_H
下面是subclass of LineEdit
#ifndef INTEDIT_H
#define INTEDIT_H
#include "lineedit.h"
class IntEditPrivate;
class IntEdit:public LineEdit
{
Q_OBJECT
public:
explicit IntEdit(QWidget *parent=nullptr);
virtual ~IntEdit();
protected:
private:
Q_DECLARE_PRIVATE(IntEdit)
};
#endif // INTEDIT_H
#include "intedit.h"
#include "lineedit_p.h"
class IntEditPrivate:public LineEditPrivate{
Q_DECLARE_PUBLIC(IntEdit)
public:
IntEditPrivate(){}
~IntEditPrivate(){}
QString test;
};
IntEdit::IntEdit(QWidget *parent):
LineEdit(*new IntEditPrivate,parent)
{
Q_D(IntEdit);
d->test = "AAA";
}
IntEdit::~IntEdit()
{
}
627

被折叠的 条评论
为什么被折叠?



