Qt的封装性d指针和q指针

d指针

Qt对于数据的封装算比较高明的了,其实原理就是把接口和实现分开,类似于如下结构:

class A
{
    class APrivate;
    APrivate *pData;
    
    public:
    A();
    ~A();
    ...
}

这样,接口类A只负责描述希望调用者看到的,而真正的细节都在APrivate类中,当然这是我个人的理解,Qt的实现要复杂的多。

以QWidget为例

先看代码:

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
    : QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
    QT_TRY {
        d_func()->init(parent, f);
    } QT_CATCH(...) {
        QWidgetExceptionCleaner::cleanup(this, d_func());
        QT_RETHROW;
    }
}

这个是QWidget的构造函数,接着往下看:

/*!
    \internal
*/
QObject::QObject(QObjectPrivate &dd, QObject *parent)
    : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    ...
}

这个是QObject的构造函数,看到有个d_ptr,类型为QScopedPointer<QObjectData>,现在好像明白了什么,在QWidget的构造函数中new了一个QWidgetPrivate对象,然后保存到基类的d_ptr中。

这里有两个宏定义,可以获取当前类的d指针,就是Q_D,实现如下:

#define Q_D(Class) Class##Private * const d = d_func()

这里有个d_func(),这时什么?不急,在Q_D定义的上方,就有一个Q_DECLARE_PRIVATE定义:

#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
friend class Class##Private;

接着就是:

template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }

现在应该明白了,Qt里面细节都放在了Class##Private的类中,也算是一种定好的命名格式。

Q_DECLARE_PRIVATE这个是在类声明的时候调用Q_DECLARE_PRIVATE(QWidget)

只要在使用d指针之前,加上Q_D(QWidget);就可以了。

q指针

与d指针相反,q指针是给Class##Private类调用的,是获取接口类的指针,同样有一个Q_Q宏定义:

#define Q_Q(Class) Class * const q = q_func()

同样,需要在Class##Private类声明出,调用Q_DECLARE_PUBLIC

#define Q_DECLARE_PUBLIC(Class)                                    \
inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
friend class Class;

更多细节可还要继续研究。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt使用d指针和q指针来实现封装和隐藏内部实现细节,以及提供更好的代码可读和可维护。同时,Qt还使用命名空间来组织和管理类和函数。 下面是一个示例代码,演示了Qt中如何使用d指针、q指针和命名空间: ```cpp // counter.h #ifndef COUNTER_H #define COUNTER_H #include <QObject> namespace MyNamespace { class CounterPrivate; // 前向声明 class Counter : public QObject { Q_OBJECT public: explicit Counter(QObject *parent = nullptr); ~Counter(); void increment(); void decrement(); int value() const; private: CounterPrivate *d_ptr; // d指针 }; } #endif // COUNTER_H // counter.cpp #include "counter.h" namespace MyNamespace { class CounterPrivate { public: int count; }; Counter::Counter(QObject *parent) : QObject(parent), d_ptr(new CounterPrivate) { d_ptr->count = 0; } Counter::~Counter() { delete d_ptr; } void Counter::increment() { ++d_ptr->count; } void Counter::decrement() { --d_ptr->count; } int Counter::value() const { return d_ptr->count; } } // main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include "counter.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); MyNamespace::Counter counter; QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("Counter", &counter); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } ``` 在这个示例中,我们定义了一个名为Counter的类,它位于MyNamespace命名空间中。Counter类使用了d指针来隐藏内部实现细节,并提供了increment、decrement和value等公共接口来操作计数器的值。在main.cpp中,我们创建了Counter的实例,并将其作为上下文属传递给QML引擎。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值