qt基础——QObject类
QObject
概述
QObject类是所有使用元对象系统的基类,也就是说,一个类如果直接或间接继承于QObject,它就可以使用信号与槽、属性等特性。
类结构
综述
QObjectData封装数据,QObjectPrivate封装线程处理,信号和槽机制等具体的实现
使用了Pimpl模式,是常用的C++设计模式。基本做法通过一个外部可见类中的指针指向具体的实现,核心思想是将类的实现细节从其接口中分离出来。当我们修改类的私有成员或实现时,不需要重新编译使用该类的所有代码,因为它们只依赖于类的接口,而不是实现。这可以大大减少项目的编译时间,特别是在大型项目中。
QObject类
QObject类成员变量及构造函数:
protected:
QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_D(QObject);//#define Q_D(Class) Class##Private * const d = d_func()
d_ptr->q_ptr = this;
auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
threadData->ref();
d->threadData.storeRelaxed(threadData);
if (parent) {
QT_TRY {
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
parent = nullptr;
if (d->isWidget) {
if (parent) {
d->parent = parent;
d->parent->d_func()->children.append(this);
}
// no events sent here, this is done at the end of the QWidget constructor
} else {
setParent(parent);
}
} QT_CATCH(...) {
threadData->deref();
QT_RETHROW;
}
}
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
protected:
QScopedPointer<QObjectData> d_ptr;
static const QMetaObject staticQtMetaObject;
QObjectData类
QObjectData类成员变量:
public:
QObject *q_ptr;
QObject *parent;
QObjectList children;
uint isWidget : 1;
uint blockSig : 1;
uint wasDeleted : 1;
uint isDeletingChildren : 1;
uint sendChildEvents : 1;
uint receiveChildEvents : 1;
uint isWindow : 1; //for QWindow
uint deleteLaterCalled : 1;
uint unused : 24;
int postedEvents;
QDynamicMetaObjectData *metaObject;
QObjectPrivate类
QObjectPrivate类:
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;
};
typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
struct Connection;
struct SignalVector;
struct ConnectionOrSignalVector {
union {
// linked list of orphaned connections that need cleaning up
ConnectionOrSignalVector *nextInOrphanList;
// linked list of connections connected to slots in this object
Connection *next;
};
};
struct Connection : public ConnectionOrSignalVector
{
// linked list of connections connected to slots in this object, next is in base class
Connection **prev;
// linked list of connections connected to signals in this object
QAtomicPointer<Connection> nextConnectionList;
Connection *prevConnectionList;
QObject *sender;
QAtomicPointer<QObject> receiver;
QAtomicPointer<QThreadData> receiverThreadData;
union {
StaticMetaCallFunction callFunction;
QtPrivate::QSlotObjectBase *slotObj;
};
QAtomicPointer<const int> argumentTypes;
QAtomicInt ref_;
uint id = 0;
ushort method_offset;
ushort method_relative;
signed int 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;
};
// ConnectionList is a singly-linked list
struct ConnectionList {
QAtomicPointer<Connection> first;
QAtomicPointer<Connection> last;
};
struct Sender
{
Sender(QObject *receiver, QObject *sender, int signal)
: receiver(receiver), sender(sender), signal(signal)
{
if (receiver) {
ConnectionData *cd = receiver->d_func()->connections.loadRelaxed();
previous = cd->currentSender;
cd->currentSender = this;
}
}
~Sender()
{
if (receiver)
receiver->d_func()->connections.loadRelaxed()->currentSender = previous;
}
void receiverDeleted()
{
Sender *s = this;
while (s) {
s->receiver = nullptr;
s = s->previous;
}
}
Sender *previous;
QObject *receiver;
QObject *sender;
int signal;
};
struct SignalVector : public ConnectionOrSignalVector {
quintptr allocated;
// ConnectionList signals[]
ConnectionList &at(int i)
{
return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
}
const ConnectionList &at(int i) const
{
return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
}
int count() const { return static_cast<int>(allocated); }
};
/*
This contains the all connections from and to an object.
The signalVector contains the lists of connections for a given signal. The index in the vector correspond
to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
any signal emission. This is done by connecting to signal index -1.
This vector is protected by the object mutex (signalSlotLock())
Each Connection is also part of a 'senders' linked list. This one contains all connections connected
to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
linked list.
*/
struct ConnectionData {
// the id below is used to avoid activating new connections. When the object gets
// deleted it's set to 0, so that signal emission stops
QAtomicInteger<uint> currentConnectionId;
QAtomicInt ref;
QAtomicPointer<SignalVector> signalVector;
Connection *senders = nullptr;
Sender *currentSender = nullptr; // object currently activating the object
QAtomicPointer<Connection> orphaned;
enum LockPolicy {
NeedToLock,
// Beware that we need to temporarily release the lock
// and thus calling code must carefully consider whether
// invariants still hold.
AlreadyLockedAndTemporarilyReleasingLock
};
};
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);
public:
ExtraData *extraData; // extra data set by the user
// This atomic requires acquire/release semantics in a few places,
// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
// because postEvent is thread-safe.
// However, most of the code paths involving QObject are only reentrant and
// not thread-safe, so synchronization should not be necessary there.
QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
QAtomicPointer<ConnectionData> connections;
union {
QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
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;
};
元对象系统
概述
每个 QObject 及其子类的实例都有一个自动创建的元对象(每一个插入Q_OBJECT宏的类定义文件都会有moc自动生成相应的cpp文件,里面包含了用户定义的各种元数据信息),元对象是 QMetaObject 类型的实例。元对象存储了类的实例所属类的各种元数据,包括类信息元数据、方法元数据、属性元数据等,所以,元对象实质上是对类的描述。
Q_OBJECT宏
public: static const QMetaObject staticMetaObject;
//moc文件中定义
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
static inline QString tr(const char *s, const char *c = nullptr, int n = -1) {
return staticMetaObject.tr(s, c, n);
}
__attribute__ ((__deprecated__)) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) {
return staticMetaObject.tr(s, c, n);
}
private: __attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
struct QPrivateSignal {
};
QMetaObject类数据
struct { // private data
SuperData superdata;//基类元数据
const QByteArrayData *stringdata;//一段字符串内存块,包含MetaObject信息之字符串信息
const uint *data;//一段二级制内存块,实际是QMetaObjectPrivate结构体
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_metacall;
const SuperData *relatedMetaObjects;
void *extradata; //reserved for future use
} d;
struct QMetaObjectPrivate
{
// revision 7 is Qt 5.0 everything lower is not supported
// revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
int flags;
int signalCount;
moc文件
写一个窗口
class Widget : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString propertyA READ getPropertyA WRITE setPropertyA RESET resetPropertyA DESIGNABLE true SCRIPTABLE true STORED true USER false)
Q_PROPERTY(QString propertyB READ getPropertyB WRITE setPropertyB RESET resetPropertyB)
Q_CLASSINFO("Author", "Long")
Q_CLASSINFO("Version", "ObjectV1.0")
Q_ENUMS(TestEnum)
public:
enum TestEnum {
EnumValueA,
EnumValueB
};
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
signals:
void click();
void press();
public slots:
void onclick();
void onpress();
};
编译生成后得到一个moc_widget.cpp文件,一部分代码如下
//QMetaObject::d.stringdata指向的结构体
struct qt_meta_stringdata_Widget_t {
QByteArrayData data[15];
char stringdata0[118];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_Widget_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {
{
QT_MOC_LITERAL(0, 0, 6), // "Widget" 序号,起始,个数
QT_MOC_LITERAL(1, 7, 6), // "Author"
QT_MOC_LITERAL(2, 14, 4), // "Long"
QT_MOC_LITERAL(3, 19, 7), // "Version"
QT_MOC_LITERAL(4, 27, 10), // "ObjectV1.0"
QT_MOC_LITERAL(5, 38, 5), // "click"
QT_MOC_LITERAL(6, 44, 0), // ""
QT_MOC_LITERAL(7, 45, 5), // "press"
QT_MOC_LITERAL(8, 51, 7), // "onclick"
QT_MOC_LITERAL(9, 59, 7), // "onpress"
QT_MOC_LITERAL(10, 67, 9), // "propertyA"
QT_MOC_LITERAL(11, 77, 9), // "propertyB"
QT_MOC_LITERAL(12, 87, 8), // "TestEnum"
QT_MOC_LITERAL(13, 96, 10), // "EnumValueA"
QT_MOC_LITERAL(14, 107, 10) // "EnumValueB"
},
"Widget\0Author\0Long\0Version\0ObjectV1.0\0"
"click\0\0press\0onclick\0onpress\0propertyA\0"
"propertyB\0TestEnum\0EnumValueA\0EnumValueB"
};
#undef QT_MOC_LITERAL
//QMetaObject::d.data指向的结构体
static const uint qt_meta_data_Widget[] = {
// content:
8, // revision 版本号
0, // classname qt_meta_stringdata_Widget的索引
2, 14, // classinfo 个数,qt_meta_data_Widget的索引
4, 18, // methods
2, 42, // properties
1, 48, // enums/sets
0, 0, // constructors
0, // flags
2, // signalCount
// classinfo: key, value qt_meta_stringdata_Widget的索引
1, 2,
3, 4,
// signals: name, argc, parameters, tag, flags
5, 0, 38, 6, 0x06 /* Public */,
7, 0, 39, 6, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
8, 0, 40, 6, 0x0a /* Public */,
9, 0, 41, 6, 0x0a /* Public */,
// signals: parameters
QMetaType::Void,
QMetaType::Void,
// slots: parameters
QMetaType::Void,
QMetaType::Void,
// properties: name, type, flags
10, QMetaType::QString, 0x00095107,
11, QMetaType::QString, 0x00095107,
// enums: name, alias, flags, count, data
12, 12, 0x0, 2, 53,
// enum data: key, value
13, uint(Widget::EnumValueA),
14, uint(Widget::EnumValueB),
0 // eod
};
信号与槽
连接函数
检查参数
首先检查参数是否正确
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
typedef QtPrivate::FunctionPointer<Func2> SlotType;
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"No Q_OBJECT in the class with the signal");
//compilation error if the arguments does not match.
Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
"The slot requires more arguments than the signal provides.");
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
"Signal and slot arguments are not compatible.");
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
"Return type of the slot is not compatible with the return type of the signal.");
const int *types = nullptr;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
return connectImpl(sender, reinterpret_cast<void **>(&signal),
receiver, reinterpret_cast<void **>(&slot),
new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
}
查找索引
根据函数地址匹配查找信号的索引
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
if (!signal) {
qWarning("QObject::connect: invalid nullptr parameter");
if (slotObj)
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
int signal_index = -1;
void *args[] = { &signal_index, signal };
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
break;
}
if (!senderMetaObject) {
qWarning("QObject::connect: signal not found in %s", sender->metaObject()->className());
slotObj->destroyIfLastRef();
return QMetaObject::Connection(nullptr);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
}
构造连接对象
构造Connection对象,记录信号与槽所在对象指针、连接类型、信号函数索引、槽函数地址等信息;添加到发送者的连接队列中
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
if (!sender || !receiver || !slotObj || !senderMetaObject) {
const char *senderString = sender ? sender->metaObject()->className()
: senderMetaObject ? senderMetaObject->className()
: "Unknown";
const char *receiverString = receiver ? receiver->metaObject()->className()
: "Unknown";
qWarning("QObject::connect(%s, %s): invalid nullptr parameter", senderString, receiverString);
if (slotObj)
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
QObject *s = const_cast<QObject *>(sender);
QObject *r = const_cast<QObject *>(receiver);
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
if (connections->signalVectorCount() > signal_index) {
const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
while (c2) {
if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
c2 = c2->nextConnectionList.loadRelaxed();
}
}
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
}
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
c->sender = s;
c->signal_index = signal_index;
QThreadData *td = r->d_func()->threadData;
td->ref();
c->receiverThreadData.storeRelaxed(td);
c->receiver.storeRelaxed(r);
c->slotObj = slotObj;
c->connectionType = type;
c->isSlotObject = true;
if (types) {
c->argumentTypes.storeRelaxed(types);
c->ownArgumentTypes = false;
}
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
QMetaObject::Connection ret(c.release());
locker.unlock();
QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
Q_ASSERT(method.isValid());
s->connectNotify(method);
return ret;
}
连接队列组织如下
发送信号
信号函数
信号在moc文件中生成
// SIGNAL 0
void Widget::click()
{
QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}
// SIGNAL 1
void Widget::press()
{
QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}
激活函数
查找信号索引
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
int signal_index = signalOffset + local_signal_index;
if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
doActivate<true>(sender, signal_index, argv);
else
doActivate<false>(sender, signal_index, argv);
}
函数调用
doActivate函数会根据信号索引检查该信号是否存在连接,取出指定信号索引处的connectionList对象,遍历,不在同一线程放队列则放入接受者线程事件队列( QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev);)
在同一线程有几种情况如下
if (c->isSlotObject) {
c->slotObj->ref();
struct Deleter {
void operator()(QtPrivate::QSlotObjectBase *slot) const {
if (slot) slot->destroyIfLastRef();
}
};
const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};
{
Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());
obj->call(receiver, argv);
}
} else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
const int method_relative = c->method_relative;
const auto callFunction = c->callFunction;
const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
}
if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
signal_spy_set->slot_end_callback(receiver, methodIndex);
} else {
const int method = c->method_relative + c->method_offset;
if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
signal_spy_set->slot_begin_callback(receiver, method, argv);
}
{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
}
if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
signal_spy_set->slot_end_callback(receiver, method);
}
第一种方式——QSlotObject模板
第一种:有QSlotObject对象,则调用父类的call函数,其调用m_impl实际是impl函数
inline void QSlotObjectBase::call(QObject *r, void **a) { m_impl(Call, this, r, a, nullptr); }
QSlotObject函数包装器,connect函数在调用connectImpl方法对QSQlotObject模板类实例化时可以推导出 QSQlotObject模板参数类型。
Func对应槽成员函数指针类型, Args对应List类型( 函数形参类型列表,形参类型链表),R对应信号返回值类型。
template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
{
typedef QtPrivate::FunctionPointer<Func> FuncType;
Func function;
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
{
switch (which) {
case Destroy:
delete static_cast<QSlotObject*>(this_);
break;
case Call:
FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
break;
case Compare:
*ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
break;
case NumOperations: ;
}
}
public:
explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
};
FunctionPointer模版
FunctionPointer模版为萃取器。可以提取类成员函数指针类型所属的类类型。 提取类成员函数指针类型函数形参参数包类型(形参列表打包到List模板元函数中)。提取类成员函数指针返回值类型。重定义类成员函数指针类型。提取类成员函数指针类型的形参数量和是否为类的成员函数枚举值。提供一个此函数指针类型的分发调用静态方法。
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
{
typedef Obj Object;
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Args...);
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
template <typename SignalArgs, typename R>
static void call(Function f, Obj *o, void **arg) {
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
}
};
template <typename, typename, typename, typename> struct FunctorCall;
template <int... II, typename... SignalArgs, typename R, typename Function>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
static void call(Function &f, void **arg) {
f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> {
static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) {
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};
第二种
第二种用于另一个connect函数:不做说明
QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
int signal_index, const QMetaObject *smeta,
const QObject *receiver, int method_index,
const QMetaObject *rmeta, int type, int *types)
第三种——qt_metacall函数
第三种:判断QObjectData中QDynamicMetaObjectData是否存在,不存在则调用qt_metacall函数,也就是moc文件中的
int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
{
if (object->d_ptr->metaObject)
return object->d_ptr->metaObject->metaCall(object, cl, idx, argv);
else
return object->qt_metacall(cl, idx, argv);
}
int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 4)
qt_static_metacall(this, _c, _id, _a);
_id -= 4;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 4)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 4;
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty
|| _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {
qt_static_metacall(this, _c, _id, _a);
_id -= 2;
} else if (_c == QMetaObject::QueryPropertyDesignable) {
_id -= 2;
} else if (_c == QMetaObject::QueryPropertyScriptable) {
_id -= 2;
} else if (_c == QMetaObject::QueryPropertyStored) {
_id -= 2;
} else if (_c == QMetaObject::QueryPropertyEditable) {
_id -= 2;
} else if (_c == QMetaObject::QueryPropertyUser) {
_id -= 2;
}
#endif // QT_NO_PROPERTIES
return _id;
}
void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->click(); break;
case 1: _t->press(); break;
case 2: _t->onclick(); break;
case 3: _t->onpress(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Widget::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Widget::click)) {
*result = 0;
return;
}
}
{
using _t = void (Widget::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Widget::press)) {
*result = 1;
return;
}
}
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty) {
auto *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: *reinterpret_cast< QString*>(_v) = _t->getPropertyA(); break;
case 1: *reinterpret_cast< QString*>(_v) = _t->getPropertyB(); break;
default: break;
}
} else if (_c == QMetaObject::WriteProperty) {
auto *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: _t->setPropertyA(*reinterpret_cast< QString*>(_v)); break;
case 1: _t->setPropertyB(*reinterpret_cast< QString*>(_v)); break;
default: break;
}
} else if (_c == QMetaObject::ResetProperty) {
Widget *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->resetPropertyA(); break;
case 1: _t->resetPropertyB(); break;
default: break;
}
}
#endif // QT_NO_PROPERTIES
Q_UNUSED(_a);
}
属性系统
静态属性
可以使用宏定义静态属性,而属性元数据放在moc文件中
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
动态属性
qt还允许在不修改类定义的情况下动态为对象添加属性(setProperty函数与Property函数),查看setProperty函数代码发现是放在QObjectPrivate::ExtraData中的
int id = meta->indexOfProperty(name);
if (id < 0) {
if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
const int idx = d->extraData->propertyNames.indexOf(name);
if (!value.isValid()) {
if (idx == -1)
return false;
d->extraData->propertyNames.removeAt(idx);
d->extraData->propertyValues.removeAt(idx);
} else {
if (idx == -1) {
d->extraData->propertyNames.append(name);
d->extraData->propertyValues.append(value);
} else {
if (value.userType() == d->extraData->propertyValues.at(idx).userType()
&& value == d->extraData->propertyValues.at(idx))
return false;
d->extraData->propertyValues[idx] = value;
}
}
QDynamicPropertyChangeEvent ev(name);
QCoreApplication::sendEvent(this, &ev);
return false;
}
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;
};
对象树
继承于QObject的对象以对象树的形式组织的,当设置了父对象时,会被添加到父对象的子对象列表中(QObjectData中的children::QObjectList ),父对象被删除时,会首先删除它的全部子对象,简化了内存回收。
参考文档
Qt6 C++开发指南——王维波 栗宝鹃 侯春望
QT源码剖析-QT对象通信机制信号槽的绑定具体实现
QT框架源码链接