吉林科技网站建设,营销策划方案100例,广州从化发布,鞍山百姓网元对象#xff08;meta object#xff09;意思是描述另一个对象结构的对象#xff0c;比如获得一个对象有多少成员函数#xff0c;有哪些属性。在Qt中#xff0c;我们将要用到的是QMetaObject这个类。
元对象系统基于以下3点#xff1a;
以QObject作为基类#xff1b;…元对象meta object意思是描述另一个对象结构的对象比如获得一个对象有多少成员函数有哪些属性。在Qt中我们将要用到的是QMetaObject这个类。
元对象系统基于以下3点
以QObject作为基类类声明的私有区域中Q_Object宏指令使我们能够使用元对象的特性比如动态属性、信号、槽等元对象编译器Meta-Object Compiler moc为QObject子类生成具有元对象特性的代码
我们可以通过QObject类的一个成员函数获得该类的元对象
QMetaObject *QObject::metaObject() const
通过这个元对象进而可以获取一个QObject对象的更多信息
返回运行时类的名称不需要C中的运行时类型识别机制RTTI
QMetaObject::className() 返回类中方法的个数
QMetaObject::methodCount()
以上只是元对象的简单介绍记住元对象系统的3点特性。之所以要介绍元对象因为Qt中很多用法是基于元对象的如果不支持元对象比如没有继承自QObject那么很多东西将无法使用
类型识别
众所周知C中使用dynamic_cast和typeid这两个运算符进行运行时类型识别RTII但是Qt提供另外两种运行时类型识别方法
qobject_cast 和 QObject::inherits()
看名字就可以知道这两个方法都是基于QObject的也就是元对象系统。
if (QLabel *label qobject_castQLabel *(obj))
{label-setText(tr(Ping));
}
else if (QPushButton *button qobject_castQPushButton *(obj))
{button-setText(tr(Pong!));
}
qobject_cast
qobject_cast 是 Qt 提供的一个宏专门用于在 QObject 层次结构中进行安全的向下转型。它仅适用于继承自 QObject 的类主要用于在使用 Qt 的对象树时通过指针进行类型转换。如果对象类型不匹配qobject_cast 返回 nullptr。
dynamic_cast
dynamic_cast 是 C 的运行时类型识别RTTI操作符用于在 C 的继承层次结构中执行类型安全的向下转型。它对于所有的 C 类型都有效不仅仅是 QObject 的派生类。如果类型不匹配dynamic_cast 返回 nullptr对于指针或抛出 std::bad_cast 异常对于引用。
QObject::inherits(const char *className)的速度相对慢一些所以尽可能使用qobject_cast。
Qt中的属性
1. 自定义属性
我们可能已经接触到很多Qt中的属性了比如qreal类型的opacity属性表示“透明度”QRect类型的geometry表示“几何位置和大小”QPoint类型的pos属性代表“位置”。所谓属性也就是类中的一个数据成员我们可以获取get和设置set。除了Qt中一些类已经具备的属性我们还可以自定义属性也就是定义一种访问数据成员的方式。
在一个继承自QObject的类中使用 Q_PROPERTY 宏指令比如
Q_PROPERTY(bool focus READ hasFocus)Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
不要被这个用法搞晕了其实很简单刚开始指定属性类型和名称然后READ表示获取属性值的方法一般这两点是必须的。其他都是可选的比如WRITE表示设置属性值得方法MEMBER表示这个属性在类中数据成员的名称NOTIFY表示属性改变发出的信号。
2. 属性的类型
由上可知属性的类型可以是bool、QString、QRect等等我们可以通过 QVariant::Type 的枚举值获得所有可用于属性的类型。可以查到它不支持枚举类型但可以通过Q_ENUM来设置
enum Priority { High, Low, VeryHigh, VeryLow };Q_ENUM(Priority)Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
当然自定义的类型也是支持的需要通过Q_DECLARE_METATYPE 注册元类型
struct MyStruct{int i;...};Q_DECLARE_METATYPE(MyStruct)
3. 属性的读与写
我们可以直接使用get和set方法来读写属性也可以通过QObject与QMetaObject来间接地读写属性。
首先是设置属性值
比如类QAbstractButton有一个“down”的属性表示按钮是否被按下它有一个成员函数 QAbstractButton::setDown() 来改变属性值同时我们也可以通过 QObject::setProperty() 对其进行设置
QPushButton *button new QPushButton;QObject *object button;button-setDown(true);object-setProperty(down, true);
值得注意的是setProperty()这个函数不但可以改变属性值也可以在运行时动态地为对象添加属性。
接下来是读取属性值
如果有get函数可以直接调用它当然也可以通过 QObject::property() 来获取属性它的返回值是 QVariant 类型的通过 canConvert() 进行判断然后将其转换为所需的类型。
QObject *object ...const QMetaObject *metaobject object-metaObject();int count metaobject-propertyCount();for (int i0; icount; i) {QMetaProperty metaproperty metaobject-property(i);const char *name metaproperty.name();QVariant value object-property(name);...}
invokeMethod()
Qt中的信号槽机制是以元对象为基础的通过名称以类型安全的方式来间接调用槽函数。
当调用槽函数时实际是由invokeMethod()完成的。
比如显示一个窗口一般是通过show()函数来完成不过我们还能这样做
MyWidget w;QMetaObject::invokeMethod(w, show);
上面讲了如何将成员变量注册进元对象系统那么对于成员函数该怎么做呢
在声明一个类的成员函数时通过使用 Q_INVOKABLE 宏进行注册可以使它们能够被元对象系统调用。
class Window : public QWidget{Q_OBJECTpublic:Window();void normalMethod();Q_INVOKABLE void invokableMethod();};
反射机制
反射机制的特性 reflection 模式(反射模式或反射机制)是指在运行时能获取任意一个类对象的所有类型信息、属性、成员函数等信息的一种机制。
元对象系统提供的功能之一是为 QObject 派生类对象提供运行时的类型信息及数据成员的当前值等信息也就是说在运行阶段程序可以获取 QObject 派生类对象所属类的名称、父类名称、该对象的成员函数、枚举类型、数据成员等信息其实这就是反射机制。
因为 Qt 的元对象系统必须从 QObject 继承又从反射机制的主要作用可看到Qt 的元对象系统主要是为程序提供了 QObject 类对象及其派生类对象的信息也就是说不是从 QObject 派生的类对象则无法使用 Qt 的元对象系统来获取这些信息。 Qt 具体实现反射机制的方法
Qt 使用了一系列的类来实现反射机制这些类对对象的各个方面进行了描述其中QMetaObject 类描述了 QObject 及其派生类对象的所有元信息该类是 Qt 元对象系统的核心类通过该类的成员函数可以获取 QObject 及其派生类对象的所有元信息因此可以说 QMetaObject 类的对象是 Qt 中的元对象。注意要调用 QMetaObject 类中的成员函数需要使用 QMetaObject 类型的对象。
对对象的成员进行描述一个对象包含数据成员、函数成员、构造函数、枚举成员等成员在 Qt 中这些成员分别使用了不同的类对其进行描述比如函数成员使用类QMetaMethod 进行描述属性使用 QMetaProperty 类进行描述等然后使用QMetaObject 类对整个类对象进行描述比如要获取成员函数的函数名其代码如下
QMetaMethod qm metaObject-method(1); //获取索引为 1 的成员函数
qDebug()qm.name()\n; //输出该成员函数的名称。
信号和槽函数的实现原理
Qt中信号和槽的实现原理基于元对象系统Meta-Object SystemMOS。以下是信号和槽的实现原理 元对象系统 在包含信号和槽的类声明中使用 Q_OBJECT 宏。这个宏会告诉 Qt 的元对象编译器MOC处理这个类生成额外的代码。这些额外的代码包括元对象的描述信息以及支持信号和槽机制的相关数据。 元对象 Qt 的元对象是对类的额外描述它包含了类的属性、方法、信号和槽的信息。这些信息被存储在元对象表中。 信号和槽的注册 在包含信号和槽的类的构造函数中MOC 自动生成的代码会注册这些信号和槽。这个注册过程将信号和槽的信息添加到元对象表中。 连接 使用 connect 函数建立信号和槽之间的连接。在连接时Qt 运行时系统会查找元对象表找到信号和槽的信息。这时建立了信号和槽之间的关联。 emit关键字 当使用 emit 关键字发射一个信号时实际上是调用了生成的槽函数。这个槽函数内部会遍历连接列表调用所有连接到该信号的槽函数。 运行时调用 Qt 使用元对象系统在运行时实现信号和槽的调用。这样它允许在不知道类的具体实现的情况下进行动态的信号和槽的连接和调用。