【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…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
