1. 程式人生 > >學習記錄-Qt中使用Q指標和D指標

學習記錄-Qt中使用Q指標和D指標

總結網上看到的文章,使用D指標的好處如下:

1.保證程式碼的二進位制相容性;

2.隱藏實現細節;

3.提高編譯速度;

Qt關於D指標和Q指標的定義:

d_ptr指標指向私有實現類,使用如下巨集定義輔助函式和宣告友元類

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

 q_ptr指標指向父類,使用如下巨集定義輔助函式和宣告友元類

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

 使用D指標和Q指標的巨集定義

#define Q_D(Class) Class##Private * const d = d_func()  
#define Q_Q(Class) Class * const q = q_func()  
/*
   Some classes do not permit copies to be made of an object. These
   classes contains a private copy constructor and assignment
   operator to disable copying (the compiler gives an error message).
*/
#define Q_DISABLE_COPY(Class) \
    Class(const Class &) Q_DECL_EQ_DELETE;\
    Class &operator=(const Class &) Q_DECL_EQ_DELETE;

定義一個類如下:

class TestClassPrivate;
class TestClass
{
public:
    TestClass();
    ~TestClass();

private:
    TestClassPrivate * const d_ptr;
    Q_DECLARE_PRIVATE(TestClass);
};

定義一個私有類如下:

class TestClass;
class TestClassPrivate
{
public:
    TestClassPrivate(TestClass *q);

private:
    TestClass * const q_ptr;
    Q_DECLARE_PUBLIC(TestClass);
    
    int m_val1;
};

一個例項:

testclass.h

#ifndef TESTCLASS_H
#define TESTCLASS_H

#include <QObject>

class TestClassPrivate;
class TestClass
{
public:
    explicit TestClass(QObject *parent);
    ~TestClass();
    
    void doFunc();
    
private:
    void showMsg(QString str);
    
private:
    TestClassPrivate * const d_ptr;
    Q_DECLARE_PRIVATE(TestClass);
    Q_DISABLE_COPY(TestClass);
};

#endif // TESTCLASS_H

testclass.cpp

#include "testclass.h"
#include <QtDebug>

class TestClassPrivate
{
public:
    TestClassPrivate(TestClass *q) :
        q_ptr(q)
    {
    }

    void testFunc()
    {
        Q_Q(TestClass);
        q->showMsg("hello!");
    }

private:
    TestClass * const q_ptr;
    Q_DECLARE_PUBLIC(TestClass);
};


TestClass::TestClass(QObject *parent):
    d_ptr(new TestClassPrivate(this))
{

}

TestClass::~TestClass()
{
    Q_D(TestClass);
    delete d;
}

void TestClass::doFunc()
{
    Q_D(TestClass);
    d->testFunc();
}

void TestClass::showMsg(QString str)
{
    qDebug() << str;
}

以上是使用Qt自帶巨集實現。

 存在問題:

1.d_ptr需要手動釋放,有可能粗心忘記了;

2.d_ptr和q_pt的宣告看起來不夠簡潔;

問題改進:

1.使用QScopedPointer,不用關注D指標的釋放;

2.使用巨集改進使用;

#define DQ_DECLARE_PRIVATE(Class) \
    Q_DECLARE_PRIVATE(Class) \
    QScopedPointer<Class##Private> d_ptr;

#define DQ_DECLARE_PUBLIC(Class) \
    Q_DECLARE_PUBLIC(Class) \
    Class* q_ptr;

#define DQ_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)

使用例項:

dqglobal.h

#ifndef DQGLOBAL_H
#define DQGLOBAL_H

#include <QtGlobal>
#include <QScopedPointer>

#define DQ_DECLARE_PRIVATE(Class) \
    Q_DECLARE_PRIVATE(Class) \
    QScopedPointer<Class##Private> d_ptr;

#define DQ_DECLARE_PUBLIC(Class) \
    Q_DECLARE_PUBLIC(Class) \
    Class* q_ptr;

#define DQ_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)

#endif // DQGLOBAL_H

testclass.h

#ifndef TESTCLASS_H
#define TESTCLASS_H

#include <QObject>
#include "dqglobal.h"

class TestClassPrivate;
class TestClass
{
    DQ_DECLARE_PRIVATE(TestClass)
public:
    explicit TestClass(QObject *parent);
    ~TestClass();

    void doFunc();

private:
    void showMsg(QString str);

//private:
//    TestClassPrivate * const d_ptr;
//    Q_DECLARE_PRIVATE(TestClass);
//    Q_DISABLE_COPY(TestClass);
};

#endif // TESTCLASS_H

testclass.cpp

#include "testclass.h"
#include <QtDebug>

class TestClassPrivate
{
    DQ_DECLARE_PUBLIC(TestClass)
public:
    TestClassPrivate(TestClass *q) :
        q_ptr(q)
    {
    }

    void testFunc()
    {
        Q_Q(TestClass);
        q->showMsg("hello!");
    }

//private:
//    TestClass * const q_ptr;
//    Q_DECLARE_PUBLIC(TestClass);
};


TestClass::TestClass(QObject *parent):
    d_ptr(new TestClassPrivate(this))
{

}

TestClass::~TestClass()
{
//    Q_D(TestClass);
//   delete d;
}

void TestClass::doFunc()
{
    Q_D(TestClass);
    d->testFunc();
}

void TestClass::showMsg(QString str)
{
    qDebug() << str;
}