设为首页 加入收藏

TOP

[Qt开发探幽(二)]浅谈关于元对象,宏和Q_ENUM(五)
2023-09-09 10:25:47 】 浏览:210
Tags:谈关于 元对象 Q_ENUM
() const { return m_value; } public slots: void setValue(int value); signals: void valueChanged(int newValue); private: int m_value; };
注意:这个宏要求类是QObject的子类。使用Q_GADGET或Q_GADGET_EXPORT而不是Q_OBJECT来启用元对象系统对非QObject子类中的枚举的支持。

Q_OBJECT宏我们可以看到,主要是做了三件事:
1.将指定的类注册进入到元对象系统内,至于什么是元对象系统,我们接下来会说,你先知道是注册进元对象系统就行了
2.添加信号与槽函数的注册
3.注册Qt的属性系统

这三个功能其实也构成了Qt这套框架的全部,可以说Qt整套系统都是围绕着Q_OBJECT宏来做的。

1.元对象系统

元对象系统
Qt的元对象系统(Meta-Object System)为对象间通信、运行时类型信息和动态属性系统提供了信号和槽机制。元对象系统基于三个方面:

  1. QObject类为可以利用元对象系统的对象提供了一个基类。

  2. 类声明的私有部分中的Q_OBJECT宏用于启用元对象功能,如动态属性、信号和插槽。

  3. 元对象编译器(moc)为每个QObject子类提供实现元对象特性所需的代码。

我们可以理解为,元对象系统就是Qt的一个“C#化”的尝试,即将原来在C++中不可见的一切

moc工具读取一个C++源文件。如果它找到一个或多个包含Q_OBJECT宏的类声明,它将生成另一个C++源文件,该文件包含每个类的元对象代码。这个生成的源文件要么被#包含到类的源文件中,要么更常见的是,被编译并链接到类的实现中。

除了提供用于对象之间通信的信号和槽机制(引入该系统的主要原因)之外,元对象代码还提供以下附加功能:

  • QObject::metaObject()返回类的关联元对象。

  • QMetaObject::className()在运行时以字符串形式返回类名,而不需要通过C++编译器支持本机运行时类型信息(RTTI)。

  • 函数返回对象是否是继承QObject继承树中指定类的类的实例。

  • QObject::tr()转换字符串以进行国际化。

  • QObject::setProperty()和QOobject::property()按名称动态设置和获取属性。

  • QMetaObject::newInstance()构造类的一个新实例。

还可以使用qobject_cast()对qobject类执行动态强制转换。qobject_cast()函数的行为类似于标准C++dynamic_cast(),其优点是不需要RTTI支持,并且可以跨动态库边界工作。它尝试将其参数强制转换为尖括号中指定的指针类型,如果对象的类型正确(在运行时确定),则返回非零指针,如果对象类型不兼容,则返回nullptr。

虽然可以在没有Q_OBJECT宏和元对象代码的情况下使用QObject作为基类,但如果不使用Q_OBJECT宏,则信号和插槽以及此处描述的其他功能都不可用。

从元对象系统的角度来看,一个没有元代码的QObject子类等价于它最接近的有元对象代码的祖先。

这意味着,例如,QMetaObject::className()不会返回类的实际名称,而是返回该祖先的类名。
因此,我们强烈建议QObject的所有子类使用Q_OBJECT宏,无论它们是否实际使用信号、槽和属性。

2.信号与槽

在Qt中的信号与槽可以说是Qt的头牌系统,也是Qt这套东西能够如此流行的重要原因,也是整个Qt框架最重要的基石。

当然了,其实自己实现一套Qt的Signal - Slot的系统其实并不复杂,而且肯定很多人已经能开发一套类似的东西了。比如我简单打个样:

class Caller {
public:
	using CallMethod = void(*)(const QString& sModule, const QString& sDescribe, const QString& sVariable, const QVariant& extra);
	using SendCMD = void(*)(const QString& sModule, const QString& sDescribe, const QString& sVariable, const QVariant& extra);

	void RegisterCallMethod(CallMethod callback) {
		callbacks_.append(callback);
	}
	void RegisterSendCMD(SendCMD callback) {
		sendcmds_.append(callback);
	}

	void Signal_CallMethod(const QString& sModule, const QString& sDescribe, const QString& sVariable, const QVariant& extra) {
		for (CallMethod callback : callbacks_) {
			if (callback) {
				callback(sModule, sDescribe, sVariable, extra);
			}
		}
	}

	void Signal_SendCMD(const QString& sModule, const QString& sDescribe, const QString& sVariable, const QVariant& extra) {
		for (SendCMD callback : callbacks_) {
			if (callback) {
				callback(sModule, sDescribe, sVariable, extra);
			}
		}
	}

private:
	QList<CallMethod> callbacks_;
	QList<SendCMD> sendcmds_;
};

但是Qt的signal - slot 强大的地方就在于它的封装性和灵活性,各种注销注册操作相对自己写回调函数还是简单很多很多的。你想啊,原先需要这么多代码的地方,现在只需要一个宏,或者一句话,难易程度几乎无法比较。

由于Qt独特的signal索引机制,导致其网络相关的库效率可能是C++回调函数的百分之一,这是非常夸张的性能损失,但是这在某些性能不关键的场景仍然是可以接受的。

Signals & Slots

Signals 和Slots用于对象之间的通信。Signals 和Slots机制是Qt的一个核心功能,可能也是与其他框架提供的功能最不同的部分。Qt的元对象系统使Signals 和Slots成为可能。

其他工具包使用回调来实现这种通信。回调是指向函数的指针,因此,如果您希望处理函数通知您某个事件,您可以将指向另一个函数的指针(回调)传递给处理函数。然后,处理函数在适当的时候调用回调。虽然使用这种方法的成功框架确实存在,但回调可能是不直观的,并且在确保回调

首页 上一页 2 3 4 5 6 下一页 尾页 5/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++算法之旅、04 基础篇 | 第一章.. 下一篇C++系列三:QT初识

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目