首页 > 其他分享 >Qt开发思想探幽]QObject、模板继承和多继承

Qt开发思想探幽]QObject、模板继承和多继承

时间:2023-08-28 14:35:00浏览次数:42  
标签:Qt 继承 QObject 编译 对象 探幽 模板

@

目录

[Qt开发探幽]QObject、模板继承和多继承

当我们在用Qt开发一个软件框架的时候,在一个正式一点的库或者框架中,我们不可避免地想要使用继承,但是可能当我们开发完一个模块后,会发现一些问题,比如说在编译的时候发现父类会编译不通过。

先说结论:
1.Qt的QObject不支持模板继承。
2.如果需要使用QObject进行多继承的话,子对象引用的父类链至多只能含有一个QObject
3.如果使用模板类和QObject做多继承,依然会编译不通过

1. QObject为什么不允许模板继承:

  1. 元对象系统的复杂性:元对象系统(Meta-Object System)是 Qt 的一个重要特性,它允许在运行时获取对象的元信息,如类名、属性、信号、槽等。这个系统需要在编译阶段生成额外的元信息,并且在运行时维护一个元对象表。这个系统在处理模板类时会变得复杂,因为模板类的实例化和使用涉及到编译期和运行时的多个步骤,而元对象系统的设计主要针对静态类型的类层次结构。

  2. 编译期类型信息:元对象系统需要在编译期生成一些额外的类型信息,用于支持信号槽和反射等功能。模板类的实例化和类型信息在编译期可能变得模糊不清,这会导致元对象系统难以正确处理模板类的元信息。

  3. 类型擦除:C++ 模板的一个特点是类型擦除,即编译器在模板实例化时会生成不同的代码,但生成的代码是针对特定的类型的,而不是模板本身。这种类型擦除使得在运行时获取模板类型信息变得复杂,而元对象系统需要在运行时获取类型信息。

  4. 信号槽连接的动态性:信号槽机制允许在运行时动态地连接和断开信号槽。这就要求在运行时能够准确地识别信号和槽的参数类型,以便进行参数匹配。模板类的参数类型在编译期可能不确定,这给信号槽的动态连接带来挑战。

所以在继承了QObject的模板类中,编译会导致QMetaObject找不到元对象而发生编译期报错,所以请不要让任何模板类继承QObject。

你可能会问了,那类似QList和QSharedPointer类为什么可以是模板类,而且也是Qt的东西呢?这恰好是Qt这个库取巧的地方:所有的模板类都是容器,也就是说他们这个模板类中允许装入任何它们想要的东西。或者换句话说,Qt中所有的模板类,都不是QObject的子类,不然的话可以直接看头文件:QSharedPointer内部
也就是说,Qt内部其实自己也是遵循这个规则的:请不要让任何模板类继承QObject。

2.如果需要使用QObject进行多继承的话,子对象引用的父类链至多只能含有一个QObject

QObject有一个很重要的特点,就是不支持拷贝。

  1. 在 Qt 的多继承体系中,只有一个类可以拥有 QObject 功能,这个类必须是多继承链中的第一个类。QObject 类为了支持元对象系统、信号槽机制以及其他与运行时类型信息相关的功能,要求继承 QObject 的类在构造函数中通过传递 parent 参数来指定父对象。这个父对象就是用于建立对象之间关系的,例如在父对象析构时,它的子对象也会被析构。

  2. 由于 C++ 的多继承特性,当一个类需要继承多个类,而其中一个类是 QObject,为了保证 QObject 的正确功能,必须将 QObject 继承链放在多继承链的第一个位置。这是因为 QObject 继承链在构造和析构过程中有一些特殊的操作,需要在第一个类中执行。

3.如果使用模板类和QObject做多继承,编译不通过

这是因为 QObject 类需要在构造和析构过程中执行特殊的操作,以支持元对象系统、信号槽机制和其他与运行时类型信息相关的功能。而模板类的继承可能会干扰这些特殊操作,导致编译错误或者运行时问题。

QObject 的特殊操作需要在构造函数中执行,并且这些操作需要基于类的实际类型来进行。而模板类在编译时才会实例化,因此编译器在处理模板类时无法获得完整的类型信息,从而无法保证 QObject 的特殊操作能够正确地执行。

为了避免这些问题,Qt 推荐将 QObject 放在继承链的第一个位置,以确保 QObject 的特殊操作可以正确地执行。如果您的类需要多继承,可以考虑使用接口继承(纯虚函数)来实现所需的功能,以避免在多继承中使用 QObject 和模板类导致的问题。

问题场景

为什么我突然会想到这个问题呢,因为我确实遇到了,场景大概是这样的:
我现在在开发一个软件框架。我现在这个框架内的所有对象都需要包含一些信号和槽(这是为了统一上下信息的交换),我们管这个最底层的东西叫TSG_Caller,理论上我这个框架内所有的东西都应该要继承到这个TSG_Caller中,方便我进行管理:

在这里插入图片描述
它实际上只有一些信号和槽,我希望任何对象都能通过注册,在kernel内统一地操作这些信号与槽,不仅仅是一些细分的类,大类也要提供这些东西。

当我开发到一定程度之后,我细化到对某个设备的操控。于是我写了一个模板类,用来初始化一些模板类的基本类型。我希望不同的设备有不同的输入参数类型,于是我们就有了如下的设备模板类:

在这里插入图片描述
于是这里就出现问题了:QObject和模板类的继承兼容不能说不好,只能说基本完全不允许使用。当然了,这也是可以理解的,毕竟MetaObject这么强大的功能不能支持模板也是理所当然的事。

至于解决方法,那就只能改造这个设备类了,不能用模板类了,而是只能采用通用的输入类型。我这里因为输入的参数类型有限而且都是明文,所以我这里将所有的输入和输出都改成QString传输json字符串,当然了输入的字符串也要提供给外部一个判断的函数,以免外部输入错误。

修改后的接口如下:

在这里插入图片描述

不知道有没有更好的办法,也许有,但是目前我只想到这种比较简单的方法

标签:Qt,继承,QObject,编译,对象,探幽,模板
From: https://www.cnblogs.com/Leventure/p/17662191.html

相关文章

  • QT Creator 远程调试 QT 程序
    一、测试环境QTCreator版本:5.12.9开发板:rv1126开发环境:ubuntu20.04开发板内核:4.19二、配置ARM交叉编译器ARM交叉编译工具,购买开发板时,一般都会提供的打开QtCreator查看之前是否添加添加编译工具添加C工具添加C++工具配置qmake配置......
  • 『PyQt5-基础篇』| 02 Pyqt5开发环境+安装配置QtDesigner
    (02Pyqt5开发环境+安装配置QtDesigner)1Pycharm安装安装教程请参考:安装教程2Python安装下载地址:官网下载地址;根据自身系统选择版本下载:下载完成,直接双击运行,即可,安装路径可选。环境变量设置:如果安装时已经勾选了“增加环境变量”的话,就不用再设置环境变量。如果没有......
  • qt进行视频二值化 未成功 待改进
    QT+opencv使用videocapture采集视频进行二值化输出_哔哩哔哩_bilibili #ifndefMAINWINDOW_H#defineMAINWINDOW_H#include<QMainWindow>#include<QLabel>#include<QTimer>#include"opencv2/opencv.hpp"#include<iostream>usingnamespacec......
  • Qt编写网易云界面 (7) -----最新音乐实现
    今天数字要实现一下该项目的最新音乐模块,效果如图:其实这个模块的内容应该是从数据库查询然后再显示,这里就简单的写死了,以后有时间在改了。最新音乐的qss:/*最新模块*//*最新音乐*/QPushButton#ptnMusAll,#ptnMusChinese,#ptnMusEurope,#ptnMusKorea,#ptnMusJapan{colo......
  • qt5 odbc mysql 开发配置
    qt5应用odbc使用mysql 要点apt-getinstallmysql-serverapt-getinstallmysqlclient-dev配置mysql-server可以安装apt-getinstallmysql-workbenchapt-getinstallmysql-connector-odbc配置/etc/odbc.ini/etc/odbcinst.iniapt-getinstallunixodbcisqlDNS-v......
  • hibernate——继承关系以及三个subclass标签的区别
    Java类中有继承关系,相应的在hibernate中,也有继承关系,子类反应到数据库中,就有多种实现形式了,子类和父类可以映射到同一张表中,子类也可以单独映射成一张表,但是用不同的标签实现,子类表和父类表的关系也不同。在映射文件中,有三个标签可以实现继承关系,分别是:subclass、joined-subclass、......
  • 基于QT和C++实现的停车场管理系统
    基于QT和C++实现的停车场管理系统停车场管理系统简介一、 问题描述设停车场是一个可停放若干辆辆汽车的狭多层平面区域,且只有一个大门可供汽车进出。若车场内已停满汽车,则后来的汽车只能在门外的狭长便道上等候,一旦停车场内有车开走,则排在便道上的第一辆车即可进入。每辆停放在......
  • Qt简易读取视频
    #include"mainwindow.h"#include"ui_mainwindow.h"#include<QMediaPlayer>#include<QtMultimedia/QMultimedia>#include<QtMultimediaWidgets/QVideoWidget>MainWindow::MainWindow(QWidget*parent):QMainWindow(pare......
  • 创建多线程继承Thread和实现Runnable以及synchronized的注意事项
    关于创建多线程继承Thread和实现Runnable以及synchronized的注意事项以下是利用多线程模拟购票的代码publicclassSell{publicstaticvoidmain(String[]args){Ticketticket=newTicket();Ticketticket1=newTicket();ticket.star......
  • 03 继承Tread类
    packageTreadDemo;//创建线程方式一:继承Tread类,重写run()方法,start()方法调用//主线程与其他线程可能一起执行//线程不一定立即执行,cpu安排调度publicclassTest03_TreadextendsThread{//main()线程,主线程publicstaticvoidmain(String[]args){......