讀QT5.7原始碼(七)QObjectData 和 QObjectPrivate
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分享(七)——Buttons和Dropdown
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筆記(七)Map和Set
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開發來一發(七)Redis和Memcached
1、Redis簡介 Redis是一個Key-Value儲存系統,可以支援String、List、Set等作為value進行儲存,並且支援push/pop、add/remove及取交集並集和差集及更豐富的操作,且保證這些操作的原子性,另外還支援排序。 Redis資料是放在記憶體中的,但會週期性
Java併發程式設計的藝術筆記(七)——CountDownLatch和CyclicBarrier
一.等待多執行緒完成的CountDownLatch CountDownLatch允許一個或多個執行緒等待其他執行緒完成操作 例: (1)開啟多個執行緒分塊下載一個大檔案,每個執行緒只下載固定的一截,最後由另外一個執行緒來拼接所有的分段;解析一個Excel裡多個sheet的資料,此時可以考慮使用多執行緒,