【50.qt基础——QObject类】

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框架源码链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值