1. 程式人生 > >讀QT5.7原始碼(七)QObjectData 和 QObjectPrivate

讀QT5.7原始碼(七)QObjectData 和 QObjectPrivate

在QObject中定義了一個保護許可權的成員變數 d_ptr
protected:
    QScopedPointer<QObjectData> d_ptr;

QScopePointer<> 是一個模板類,維護特定型別的指標,這裡d_ptr  相當於一個QObjectData物件的指標。

QObject 幾乎是所有QT中的類的基類,因此QT中每個繼承於Qobject的類都有這個指標,指向一個動態分配的QObjectData物件。

QObjectData類的定義

class Q_CORE_EXPORT QObjectData {
public:
    virtual ~QObjectData() = 0;
    QObject *q_ptr;    物件this指標
    QObject *parent;   父物件指標
    QObjectList children;       typedef QList<QObject*> QObjectList;     這個是物件的子物件連結串列,區別於父類和子類

    uint isWidget : 1;   是否是Wideget型別
    uint blockSig : 1;      是否處於訊號阻塞
    uint wasDeleted : 1;     防止多次delete物件
    uint isDeletingChildren : 1;   是否在delete子物件
    uint sendChildEvents : 1;       是否向父物件報告物件插入和刪除事件  應該為true
    uint receiveChildEvents : 1;     是否接收子物件的事件訊息    應該為ture
    uint isWindow : 1; //for QWindow
    uint unused : 25;
    int postedEvents;
    QDynamicMetaObjectData *metaObject;
    QMetaObject *dynamicMetaObject() const;
};


在QObject的建構函式中對d_ptr進行了初始化

QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)     這裡是構建了一個QObjectPrivate物件,並將其指標賦給d_ptr
{
....................................省略
}


QObjectPrivate  是QObjectData的子類,這樣就合情合理了。 事實上這個類是如此的重要,也是資訊量很大的一個結構

class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)

public:
    struct ExtraData
    {
        ExtraData() {}
    #ifndef QT_NO_USERDATA
        QVector<QObjectUserData *> userData;
    #endif
        QList<QByteArray> propertyNames;
        QVector<QVariant> propertyValues;
        QVector<int> runningTimers;
        QList<QPointer<QObject> > eventFilters;
        QString objectName;
    };                              //一些結構分別用來存放物件所屬類的 property 執行時間等資訊

    typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
    struct Connection    //重要的結構   儲存每個訊號和槽的連線
    {
        QObject *sender;    傳送物件的指標
        QObject *receiver;   接受物件的指標
        union {
            StaticMetaCallFunction callFunction;         接受物件的qt_static_metacall函式的指標
            QtPrivate::QSlotObjectBase *slotObj;
        };
        // The next pointer for the singly-linked ConnectionList
        Connection *nextConnectionList;   
        //senders linked list
        Connection *next;
        Connection **prev;
        QAtomicPointer<const int> argumentTypes;     引數值陣列指標
        QAtomicInt ref_;
        ushort method_offset;    
        ushort method_relative;   
        uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
        ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
        ushort isSlotObject : 1;
        ushort ownArgumentTypes : 1;
        Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) {
            //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
        }
        ~Connection();
        int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
        void ref() { ref_.ref(); }
        void deref() {
            if (!ref_.deref()) {
                Q_ASSERT(!receiver);
                delete this;
            }
        }
    };
    // ConnectionList is a singly-linked list   訊號對應的槽連結串列,每一個訊號對應一個該結構,每一個連線儲存在一個connection
    struct ConnectionList {
        ConnectionList() : first(0), last(0) {}
        Connection *first;
        Connection *last;
    };

    struct Sender   
    {
        QObject *sender;
        int signal;
        int ref;
    };


    QObjectPrivate(int version = QObjectPrivateVersion);
    virtual ~QObjectPrivate();
    void deleteChildren();

    void setParent_helper(QObject *);
    void moveToThread_helper();
    void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
    void _q_reregisterTimers(void *pointer);

    bool isSender(const QObject *receiver, const char *signal) const;
    QObjectList receiverList(const char *signal) const;
    QObjectList senderList() const;

    void addConnection(int signal, Connection *c);
    void cleanConnectionLists();

    static inline Sender *setCurrentSender(QObject *receiver,
                                    Sender *sender);
    static inline void resetCurrentSender(QObject *receiver,
                                   Sender *currentSender,
                                   Sender *previousSender);

    static QObjectPrivate *get(QObject *o) {
        return o->d_func();
    }

    int signalIndex(const char *signalName, const QMetaObject **meta = 0) const;
    inline bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
    inline bool isDeclarativeSignalConnected(uint signalIdx) const;

    // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
    // the API public in QObject. This is used by QQmlNotifierEndpoint.
    inline void connectNotify(const QMetaMethod &signal);
    inline void disconnectNotify(const QMetaMethod &signal);

    template <typename Func1, typename Func2>
    static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
                                                  const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
                                                  Qt::ConnectionType type = Qt::AutoConnection);
template <typename Func1, typename Func2> static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot); static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject); static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); static bool disconnect(const QObject *sender, int signal_index, void **slot); public: ExtraData *extraData; // extra data set by the user QThreadData *threadData; // id of the thread that owns the object
QObjectConnectionListVector *connectionLists; Connection *senders; // linked list of connections connected to this object Sender *currentSender; // object currently activating the object mutable quint32 connectedSignals[2]; union { QObject *currentChildBeingDeleted; QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module }; // these objects are all used to indicate that a QObject was deleted // plus QPointer, which keeps a separate list QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; };

其中 QObjectConnectionListVector *connectionLists    是一個QVector<QObjectPrivate::ConnectionList>
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
    bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
    bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
    int inUse; //number of functions that are currently accessing this object or its connections
    QObjectPrivate::ConnectionList allsignals;

    QObjectConnectionListVector()
        : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
    { }

    QObjectPrivate::ConnectionList &operator[](int at)
    {
        if (at < 0)
            return allsignals;
        return QVector<QObjectPrivate::ConnectionList>::operator[](at);
    }
};


結構圖如下


1、QObjectList QObjectPrivate::receiverList(const char *signal) const    返回指定訊號關聯的接受物件的列表

QObjectList QObjectPrivate::receiverList(const char *signal) const
{
    Q_Q(const QObject);
    QObjectList returnValue;
    int signal_index = signalIndex(signal);   返回絕對索引
    if (signal_index < 0)
        return returnValue;
    QMutexLocker locker(signalSlotLock(q));
    if (connectionLists) {
        if (signal_index < connectionLists->count()) {
            const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;  根據索引在QVector中找到對應的ConnectionList,first指向表頭

            while (c) {
                if (c->receiver)
                    returnValue << c->receiver;
                c = c->nextConnectionList;    遍歷這個單項鍊表,將receiver不為空的新增到QObjectList
            }
        }
    }
    return returnValue;
}

2、QObjectList QObjectPrivate::senderList() const   返回連結到改物件的  物件列表

QObjectList QObjectPrivate::senderList() const
{
    QObjectList returnValue;
    QMutexLocker locker(signalSlotLock(q_func()));
    for (Connection *c = senders; c; c = c->next)
        returnValue << c->sender;                       通過遍歷senders
    return returnValue;
}

3、int QObjectPrivate::signalIndex  const char *signalName,const QMetaObject **meta) const      返回訊號的絕對索引
int QObjectPrivate::signalIndex(const char *signalName,
                                const QMetaObject **meta) const
{
    Q_Q(const QObject);  //巨集 q=this
    const QMetaObject *base = q->metaObject();
    Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
    QArgumentTypeArray types;
    QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);  
    int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
            &base, name, types.size(), types.constData());
    if (relative_index < 0)
        return relative_index;
    relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
    if (meta)
        *meta = base;
    return relative_index + QMetaObjectPrivate::signalOffset(base);     +offset   返回絕對索引    索引相對於全部的訊號包括繼承來的
}
4、void QObjectPrivate::addConnection(int signal, Connection *c)    將某個訊號關聯的Connection  加到連結串列中
void QObjectPrivate::addConnection(int signal, Connection *c)
{
    Q_ASSERT(c->sender == q_ptr);
    if (!connectionLists)
        connectionLists = new QObjectConnectionListVector();   如果容器為空建立它
    if (signal >= connectionLists->count())
        connectionLists->resize(signal + 1);                 根據訊號的索引,如果容器對應的索引位置為空,表示還沒有為訊號連線任何函式,調整容器大小,
                                                              在對應的位置構建訊號關聯的ConnectionList
    ConnectionList &connectionList = (*connectionLists)[signal];
    if (connectionList.last) {
        connectionList.last->nextConnectionList = c;
    } else {
        connectionList.first = c;   
    }
    connectionList.last = c;      //.last始終指向最後加入的connection

    cleanConnectionLists();

    c->prev = &(QObjectPrivate::get(c->receiver)->senders);
    c->next = *c->prev;
    *c->prev = c;                               //加到接收物件的senders的連結串列裡
    if (c->next)
        c->next->prev = &c->next;

    if (signal < 0) {
        connectedSignals[0] = connectedSignals[1] = ~0;
    } else if (signal < (int)sizeof(connectedSignals) * 8) {
        connectedSignals[signal >> 5] |= (1 << (signal & 0x1f));
    }
}


相關推薦

QT5.7原始碼QObjectData QObjectPrivate

在QObject中定義了一個保護許可權的成員變數 d_ptrprotected: QScopedPointer<QObjectData> d_ptr; QScopePointer<> 是一個模板類,維護特定型別的指標,這裡d_ptr  相當

QT5.7原始碼QArrayData QTypedArrayData

QArrayData QTypedArrayData這兩個類是配套的,後者是以前者為基礎的類模板,以方便對不同型別的陣列提供抽象管理。 他們被定義下同一個頭檔案和原始檔中,分別是QarraryData.h 和 QarraryData.cpp  位於qtcode資料夾中 Q

Zookeeper 原始碼請求處理

Zookeeper 原始碼(七)請求處理 以單機啟動為例講解 Zookeeper 是如何處理請求的。先回顧一下單機時的請求處理鏈。 // 單機包含 3 個請求鏈:PrepRequestProcessor -> SyncRequestProcessor -> FinalRequestProces

淺析Vue原始碼——render到VNode的生成

前面我們用三片文章介紹了compile解析template,完成了 template --> AST --> render function 的過程。這篇我們主要介紹一下VNode的生成過程,在此之前,我們先來簡單的瞭解一下什麼是VNode?

cas4.2.7學習cas server端登陸後根據url自定義跳轉

首先說明一下,正常的單點登陸應該都是訪問客戶端,然後跳轉到cas伺服器驗證登陸之後,返回到客戶端原來的地址, 這個是通過引數service來實現的,我們返回沒有客戶端跳轉到cas server登陸頁的時候位址列裡都會跟有這個引數。這個引數就是控制重定向的。 但是如果我們直

白話Spring原始碼:FactoryBean

看清楚是FactoryBean,不是BeanFactory,雖然他們長得很像,但作用確實天差地別,BeanFactory是bean工廠,前面的部落格已經介紹過了,他們工廠類的基礎介面,而FactoryBean是一種bean,那為什麼要有這種bean呢,和一般的bean有什麼區別呢?下面跟大家分享一下

vue原始碼Vue 的初始化之開篇

本文是學習vue原始碼,之所以轉載過來是方便自己隨時檢視,在這裡要感謝HcySunYang大神,提供的開源vue原始碼解析,寫的非常非常好,簡單易懂,比自己看要容易多了,他的文章連結地址是http://hcysun.me/vue-design/art/ 用於初始化的最終選項 $options

Spring 原始碼Spring 事務

註冊後置處理器開啟對事務的支援 @EnableTransactionManagement @EnableTransactionMa

Guice 學習常量屬性的註入 Constant and Property Inject

-a ret roc build ann class google mes ota 1、常量註入方式 package com.guice.ConstantInjectDemo; import com.google.inject.Binder; i

AngularJs的UI組件ui-Bootstrap分享——ButtonsDropdown

pre led str 屬性表 clas menu 組合 代碼 pan 原文地址:http://www.cnblogs.com/pilixiami/p/5636218.html 在ui-Bootstrap中,Buttons控件和Dropdown控件與form表單中的按鈕

redis 實驗監控性能

系統/運維 Linux redis-cli monitor可以實時看到命令情況可以跑一個性能測試redis-benchmark -c 10 -n 100000 -qredis 實驗(七)監控和性能

MySQL數據庫高級——事務

MySQL 事務 鎖MySQL數據庫高級(七)——事務和鎖 一、事務簡介 1、事務簡介 事務(Transaction) 是指作為單個邏輯工作單元執行的一系列操作。 2、事務的特性 A、原子性(Atomicity)表示組成一個事務的多個數據庫操作是一個不可分隔的原子單元,只有所有的操作執行成功,整個事務才提交,

機器學習—Adaboost 梯度提升樹GBDT

獲得 決策樹 info gin 否則 它的 均方差 但是 ont 1、Adaboost算法原理,優缺點:   理論上任何學習器都可以用於Adaboost.但一般來說,使用最廣泛的Adaboost弱學習器是決策樹和神經網絡。對於決策樹,Adaboost分類用了CART分類樹,

Java筆記MapSet

Map和Set 一)HashMap 1.Map介面 interface Map<K,V> { int size();//檢視Map中的鍵值對個數 boolean isEmpty();//是否為空 boolean containsKey(Object key);/

OAuth 2.0系列教程 請求響應

作者:Jakob Jenkov   譯者:林浩    校對:郭蕾 當客戶端應用請求授權和訪問令牌時,它傳送http請求到授權伺服器,同它的授權和令牌端點。被髮送來回的請求和響應取決於授權型別。記住,這四種授權型別: 授權碼授權 契約授權 資源擁有者金鑰證書授權 客戶端證書授權 每一種授權

HTC Vive 開發筆記啟用關閉VRTK_Pointer 指標

檢視API文件,看到的是使用VRTK_Pointer下的Toggle()方法來進行指標的開關,實際程式碼中使用如下語句gameObject.GetComponent<VRTK_Pointer>().Toggle(true);並沒有達到想要的效果,然後google之

cocos creator學習觸控鍵盤事件總結

1、處理事件在節點(cc.Node)中完成的。對於元件可以通過訪問節點this.node來註冊和監聽事件。監聽事件可以通過this.mode.on()函式來進行 this.node.on('mousedown',function(event){          conso

caffe隨記---訓練測試自己的圖片

前面也介紹了tools工具,今天來試著自己跑一下影象分類的例項 1、下載資料 我沒有用imagenet的資料,因為太大了不想下,而且反正也只是當作例程跑一下而已,所以我用的是另一位博主分享的網盤上的資料,共有500張圖片,分為大巴車、恐龍、大象、鮮花和馬五個類,每個類1

Web開發來一發RedisMemcached

1、Redis簡介 Redis是一個Key-Value儲存系統,可以支援String、List、Set等作為value進行儲存,並且支援push/pop、add/remove及取交集並集和差集及更豐富的操作,且保證這些操作的原子性,另外還支援排序。 Redis資料是放在記憶體中的,但會週期性

Java併發程式設計的藝術筆記——CountDownLatchCyclicBarrier

一.等待多執行緒完成的CountDownLatch CountDownLatch允許一個或多個執行緒等待其他執行緒完成操作 例: (1)開啟多個執行緒分塊下載一個大檔案,每個執行緒只下載固定的一截,最後由另外一個執行緒來拼接所有的分段;解析一個Excel裡多個sheet的資料,此時可以考慮使用多執行緒,