【Qt】不透明指针(Opaque Pointer)在Qt源码中的应用
目录
- 什么是不透明指针(Opaque Pointer)
- 不透明指针在Qt代码中的应用
- Qt中与不透明指针相关的一些宏
什么是不透明指针(Opaque Pointer)
GeeksforGeeks中给的定义如下:
An opaque pointer is a pointer that points to a data structure whose contents are not exposed at the time of its definition.
不透明指针是一种指针,这种指针指向的内容是不公开的。
文字描述太抽象,我们通过代码展示什么是不透明指针,为什么要使用它。
假设我们实现一个Person类,保存信息并支持打印,实现很简单:
// person.h
#ifndef _PERSON_H_
#define _PERSON_H_#include <string>class Person {
private:std::string name;
public:Person();void printInfo();
};#endif
// person.cpp
#include <iostream>
#include "foo.h"Person::Person(): name("Sam") {}void Person::printInfo() {std::cout << name << std::endl;
}
以这种方式实现,非常简单直接,足够我们自己使用了。但如果要作为共享库,提供给其他人使用,就可能出现问题。
首先,在.h
中,可以看到name属性,其他人大概可以猜测printInfo()
的实现。
其次,如果我们修改代码实现,比如Person
的属性增加一个年龄age
:
// person.h
#ifndef _PERSON_H_
#define _PERSON_H_#include <string>class Person {
private:std::string name;int age;
public:Person();void printInfo();
};#endif
// person.cpp
#include <iostream>
#include "foo.h"Person::Person(): name("Sam"), age(18) {}void Person::printInfo() {std::cout << name << " " << age << std::endl;
}
此时,依赖我们库的代码,必须重新编译,否则会Crash。
不透明指针就可以解决上面两个问题,将代码改为如下形式:
// person.h
#ifndef _PERSON_H_
#define _PERSON_H_struct PersonPrivate;
class Person {
private:PersonPrivate *d_ptr;
public:Person();void print();
};#endif
// person.cpp
#include <iostream>
#include <string>#include "foo.h"struct PersonPrivate {std::string name;PersonPrivate():name("Sam") {}
};Person::Person(): d_ptr(new PersonPrivate) {}void Person::print() {std::cout << d_ptr->name << std::endl;
}
其中d_ptr
就是不透明指针,不透明指针隐藏了更多的实现细节,另外修改增加age
时,无需修改.h
只需要修改cpp
为如下代码:
// person.cpp
#include <iostream>
#include <string>#include "foo.h"struct PersonPrivate {std::string name;int age;PersonPrivate():name("Sam"), age(10) {}
};Person::Person(): d_ptr(new PersonPrivate) {}void Person::print() {std::cout << d_ptr->name << " " << d_ptr->age << std::endl;
}
而且这种实现,依赖我们库的程序,不需要重新编译,也可以正常运行,这就是所谓binary compatibility。
不透明指针在Qt代码中的应用
以常用的QLabel为例,其源代码如下:
// qlabel.h
#ifndef QLABEL_H
#define QLABEL_H#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qframe.h>
#include <QtGui/qpicture.h>
#include <QtGui/qtextdocument.h>QT_REQUIRE_CONFIG(label);QT_BEGIN_NAMESPACEclass QLabelPrivate;class Q_WIDGETS_EXPORT QLabel : public QFrame
{Q_OBJECTQ_PROPERTY(QString text READ text WRITE setText)Q_PROPERTY(Qt::TextFormat textFormat READ textFormat WRITE setTextFormat)Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)Q_PROPERTY(bool scaledContents READ hasScaledContents WRITE setScaledContents)Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap)Q_PROPERTY(int margin READ margin WRITE setMargin)Q_PROPERTY(int indent READ indent WRITE setIndent)Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks)Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlagsWRITE setTextInteractionFlags)Q_PROPERTY(bool hasSelectedText READ hasSelectedText)Q_PROPERTY(QString selectedText READ selectedText)public:explicit QLabel(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags());explicit QLabel(const QString &text, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags());~QLabel();QString text() const;#if QT_DEPRECATED_SINCE(6,6)QPixmap pixmap(Qt::ReturnByValueConstant) const { return pixmap(); }
#endifQPixmap pixmap() const;#ifndef QT_NO_PICTURE
#if QT_DEPRECATED_SINCE(6,6)QPicture picture(Qt::ReturnByValueConstant) const { return picture(); }
#endifQPicture picture() const;
#endif
#if QT_CONFIG(movie)QMovie *movie() const;
#endifQt::TextFormat textFormat() const;void setTextFormat(Qt::TextFormat);QTextDocument::ResourceProvider resourceProvider() const;void setResourceProvider(const QTextDocument::ResourceProvider &provider);Qt::Alignment alignment() const;void setAlignment(Qt::Alignment);void setWordWrap(bool on);bool wordWrap() const;int indent() const;void setIndent(int);int margin() const;void setMargin(int);bool hasScaledContents() const;void setScaledContents(bool);QSize sizeHint() const override;QSize minimumSizeHint() const override;
#ifndef QT_NO_SHORTCUTvoid setBuddy(QWidget *);QWidget *buddy() const;
#endifint heightForWidth(int) const override;bool openExternalLinks() const;void setOpenExternalLinks(bool open);void setTextInteractionFlags(Qt::TextInteractionFlags flags);Qt::TextInteractionFlags textInteractionFlags() const;void setSelection(int, int);bool hasSelectedText() const;QString selectedText() const;int selectionStart() const;public Q_SLOTS:void setText(const QString &);void setPixmap(const QPixmap &);
#ifndef QT_NO_PICTUREvoid setPicture(const QPicture &);
#endif
#if QT_CONFIG(movie)void setMovie(QMovie *movie);
#endifvoid setNum(int);void setNum(double);void clear();Q_SIGNALS:void linkActivated(const QString& link);void linkHovered(const QString& link);protected:bool event(QEvent *e) override;void keyPressEvent(QKeyEvent *ev) override;void paintEvent(QPaintEvent *) override;void changeEvent(QEvent *) override;void mousePressEvent(QMouseEvent *ev) override;void mouseMoveEvent(QMouseEvent *ev) override;void mouseReleaseEvent(QMouseEvent *ev) override;
#ifndef QT_NO_CONTEXTMENUvoid contextMenuEvent(QContextMenuEvent *ev) override;
#endif // QT_NO_CONTEXTMENUvoid focusInEvent(QFocusEvent *ev) override;void focusOutEvent(QFocusEvent *ev) override;bool focusNextPrevChild(bool next) override;private:Q_DISABLE_COPY(QLabel)Q_DECLARE_PRIVATE(QLabel)
#if QT_CONFIG(movie)Q_PRIVATE_SLOT(d_func(), void _q_movieUpdated(const QRect&))Q_PRIVATE_SLOT(d_func(), void _q_movieResized(const QSize&))
#endifQ_PRIVATE_SLOT(d_func(), void _q_linkHovered(const QString &))#ifndef QT_NO_SHORTCUTQ_PRIVATE_SLOT(d_func(), void _q_buddyDeleted())
#endiffriend class QTipLabel;friend class QMessageBoxPrivate;friend class QBalloonTip;
};QT_END_NAMESPACE#endif // QLABEL_H
QFrame
继承自QWidget
,QWdiget
继承自QObject
和QPaintDevice
。
其中和不透明指针相关的主要是如下3个地方:
// qlabel.h
// ...
class QLabelPrivate;
class Q_WIDGETS_EXPORT QLabel : public QFrame
{// ...
private:// ...Q_DECLARE_PRIVATE(QLabel)// ....
};
// ...
QLabelPrivate
声明(只是声明,没有引用和实现)了不透明指针的类型QLabel
最终继承自QObject
,QObject
中有d_ptr
属性
Q_DECLARE_PRIVATE(QLabel)
利用宏的方式给QLabel
类添加友元QLabelPrivate
,以及获取d_ptr
的方法d_func()
至于QLabelPrivate的具体实现,我们作为外人就不得而知了。这种实现在Qt源码中随处可见
Qt中与不透明指针相关的一些宏
上面我们看到了Q_DECLARE_PRIVATE
,就是将某个类对应的Private类添加为它的友元,并声明获取d_ptr
的方法d_func()
另外还有Q_D
:
#define Q_D(Class) Class##Private * const d = d_func()
其作用是在某个类中使用其Private类的成员,比如在QLabel
实现中的某个函数中,可能就有Q_D(QLabel)
,那么该函数中可以直接使用d->
的方式调用QLabelPrivate
的成员。
相关文章:

【Qt】不透明指针(Opaque Pointer)在Qt源码中的应用
目录 什么是不透明指针(Opaque Pointer)不透明指针在Qt代码中的应用Qt中与不透明指针相关的一些宏 什么是不透明指针(Opaque Pointer) GeeksforGeeks中给的定义如下: An opaque pointer is a pointer that points to …...

【Python】牛客网—软件开发-Python专项练习
专栏文章索引:Python 1.(单选)下面哪个是Python中不可变的数据结构? A.set B.list C.tuple D.dict 可变数据类型:列表list[ ]、字典dict{ }、集合set{ }(能查询,也可更改)数据发生改…...

HBase分布式数据库的原理和架构
一、HBase简介 HBase是是一个高性能、高可靠性、面向列的分布式数据库,它是为了在廉价的硬件集群上存储大规模数据而设计的。HBase利用Hadoop HDFS作为其文件存储系统,且Hbase是基于Zookeeper的。 二、HBase架构 *图片引用 Hbase采用Master/Slave架构…...

c#类属性与字段例说说
在C#中,类属性(Properties)和字段(Fields)是两种用于存储和访问数据的机制。 属性是一种特殊的方法,通过使用get和set访问器来定义,用于读取和写入类的私有字段。属性可以提供对字段的封装&…...

Linux Centos系统 磁盘分区和文件系统管理 (深入理解)
CSDN 成就一亿技术人! 作者主页:点击! Linux专栏:点击! CSDN 成就一亿技术人! 前言———— 磁盘 在Linux系统中,磁盘是一种用于存储数据的物理设备,可以是传统的硬盘驱动器&am…...

华为配置ISP选路实现报文按运营商转发
CLI举例:配置ISP选路实现报文按运营商转发 介绍通过配置ISP选路实现报文按运营商转发的配置举例。 组网需求 如图1所示,FW作为安全网关部署在网络出口,企业分别从ISP1和ISP2租用一条链路。 企业希望访问Server 1的报文从ISP1链路转发&#…...

软件测试APP完整测试作业流程(附流程图),公司级软件测试流程化办公
目录 1. 概述 2. 软件测试流程 3. 软件测试周期人员活动图 4. 总结 1. 概述 1.1 目的 有效的保证软件质量; 有效的制定不同测试类型(软件系统测试、音频主观性测试、Field Trial、专项测试、自动化测试、性 能测试、用户体验测试)的软件…...

搭建交换机模拟环境及SSH连接,华为NSP软件入门使用教程
搭建交换机模拟环境及SSH连接,华为NSP软件入门使用教程 如果你是通过搜索搜到了这篇文章,那么一定是工作或者学习中需要用交换机,但是又没物理机测试学习,所以需要搭建本地的虚拟环境学习。 这篇文章是我进行交换机命令入门学习写…...

mineadmin 快速安装部署(docker环境)
前提条件:已安装docker 一、下载dnmp环境包 github地址:https://github.com/tomorrow-sky/dnmp gitee地址: https://gitee.com/chenjianchuan/dnmp 二、看一下dnmp包目录结构 三、打开docker-compose.yml 文件,将不需要…...
【力扣刷题练习】93. 复原 IP 地址
题目描述: 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。 例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011…...

linux查看文件内容cat,less,vi,vim
学习记录 目录 catlessvi vim cat 输出 FILE 文件的全部内容 $ cat [OPTION] FILE示例 输出 file.txt 的全部内容 $ cat file.txt查看 file1.txt 与 file2.txt 连接后的内容 $ cat file1.txt file2.txt为什么名字叫 cat? 当然和猫咪没有关系。 cat 这里是 co…...

【恒源智享云】conda虚拟环境的操作指令
conda虚拟环境的操作指令 由于虚拟环境经常会用到,但是我总忘记,所以写个博客,留作自用。 在恒源智享云上,可以直接在终端界面输入指令,例如: 查看已经存在的虚拟环境列表 conda env list查看当前虚拟…...

Flask python 开发篇:项目布局
一、背景简介 Flask应用程序可以像单个文件一样简单。就像上一篇简单实现一个接口一样,所有的东西都在一个python文件内; 然而,当项目越来越大的时候,把所有代码放在单个文件中就有点不堪重负了。 Python 项目使用 包 来管理代码…...

docker 部署prometheus+grafana
首先进行部署docker 配置阿里云依赖: curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo # 配置centos 7的镜像源 yum install -y yum-utils device-mapper-persistent-data lvm2 # 安装一些后期或需要的的一下依…...

RNN实战
本主要是利用RNN做多分类任务,在熟悉RNN训练的过程中,我们可以理解 1)超参数 batch_size和pad_size对训练过程的影响。 2)文本处理过程中是如何将文本的文字表示转化为向量表示 3)RNN梯度消失和序列长度的关系 4&#…...
从GPT入门,到R语言基础与作图、回归模型分析、混合效应模型、多元统计分析及结构方程模型、Meta分析、随机森林模型及贝叶斯回归分析综合应用等专题及实战案例
目录 专题一 GPT及大语言模型简介及使用入门 专题二 GPT与R语言基础与作图(ggplot2) 专题三 GPT与R语言回归模型(lm&glm) 专题四 GPT与混合效应模型(lmm&glmm) 专题五 GPT与多元统计分析&…...

【Android】数据安全(一) —— Sqlite加密
目录 SQLCipherSQLiteCrypt其它 SQLCipher SQLCipher 是 SQLite 数据库的的开源扩展,使用了 256 位 AES 加密,支持跨平台、零配置、数据100%加密、加密开销低至 5 -15%、占用空间小、性能出色等优点,因此非常适合保护嵌入式应用程序数据库&a…...
云原生周刊:Helm Charts 深入探究 | 2024.3.11
开源项目推荐 Glasskube Glasskube 提供了一个用于 Kubernetes 的缺失的包管理器。它具有图形用户界面(GUI)和命令行界面(CLI)。Glasskube 包是具备依赖感知、GitOps 准备和可以通过中央公共包仓库自动更新的特性。 imgpkg imgpkg(发音为:"imag…...

【C++初阶】第六站 : 模板初阶
前言: 本章知识点:泛型编程、函数模板、类模板 专栏: C初阶 目录 泛型编程 函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 4.函数模板的实例化 5.模板参数的匹配原则 类模板 类模板的定义格式 类模板的实例化 泛型编程 如何实现一…...
训练保存模型checkpoint时报错SyntaxError: invalid syntax
在使用pytorch训练保存checkpoint时,出现如下报错: rootautodl-container-745411b452-c5cebfed:~/kvasir-seg-main# python train_transunet.py --loss_function"IoULoss" --training_augmentation0File "train_transunet.py", lin…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...