当前位置: 首页 > news >正文

【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继承自QWidgetQWdiget继承自QObjectQPaintDevice

其中和不透明指针相关的主要是如下3个地方:

// qlabel.h
// ... 
class QLabelPrivate;
class Q_WIDGETS_EXPORT QLabel : public QFrame
{// ...
private:// ...Q_DECLARE_PRIVATE(QLabel)// ....
};
// ...
  • QLabelPrivate声明(只是声明,没有引用和实现)了不透明指针的类型
  • QLabel最终继承自QObjectQObject中有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源码中的应用

目录 什么是不透明指针&#xff08;Opaque Pointer&#xff09;不透明指针在Qt代码中的应用Qt中与不透明指针相关的一些宏 什么是不透明指针&#xff08;Opaque Pointer&#xff09; GeeksforGeeks中给的定义如下&#xff1a; An opaque pointer is a pointer that points to …...

【Python】牛客网—软件开发-Python专项练习

专栏文章索引&#xff1a;Python 1.&#xff08;单选&#xff09;下面哪个是Python中不可变的数据结构&#xff1f; A.set B.list C.tuple D.dict 可变数据类型&#xff1a;列表list[ ]、字典dict{ }、集合set{ }(能查询&#xff0c;也可更改)数据发生改…...

HBase分布式数据库的原理和架构

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

c#类属性与字段例说说

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

Linux Centos系统 磁盘分区和文件系统管理 (深入理解)

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; Linux专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; 前言———— 磁盘 在Linux系统中&#xff0c;磁盘是一种用于存储数据的物理设备&#xff0c;可以是传统的硬盘驱动器&am…...

华为配置ISP选路实现报文按运营商转发

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

软件测试APP完整测试作业流程(附流程图),公司级软件测试流程化办公

目录 1. 概述 2. 软件测试流程 3. 软件测试周期人员活动图 4. 总结 1. 概述 1.1 目的 有效的保证软件质量&#xff1b; 有效的制定不同测试类型&#xff08;软件系统测试、音频主观性测试、Field Trial、专项测试、自动化测试、性 能测试、用户体验测试&#xff09;的软件…...

搭建交换机模拟环境及SSH连接,华为NSP软件入门使用教程

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

mineadmin 快速安装部署(docker环境)

前提条件&#xff1a;已安装docker 一、下载dnmp环境包 github地址&#xff1a;https://github.com/tomorrow-sky/dnmp gitee地址&#xff1a; https://gitee.com/chenjianchuan/dnmp 二、看一下dnmp包目录结构 三、打开docker-compose.yml 文件&#xff0c;将不需要…...

【力扣刷题练习】93. 复原 IP 地址

题目描述&#xff1a; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址&#xff0c;但是 “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&#xff1f; 当然和猫咪没有关系。 cat 这里是 co…...

【恒源智享云】conda虚拟环境的操作指令

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

Flask python 开发篇:项目布局

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

docker 部署prometheus+grafana

首先进行部署docker 配置阿里云依赖&#xff1a; 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做多分类任务&#xff0c;在熟悉RNN训练的过程中&#xff0c;我们可以理解 1&#xff09;超参数 batch_size和pad_size对训练过程的影响。 2&#xff09;文本处理过程中是如何将文本的文字表示转化为向量表示 3&#xff09;RNN梯度消失和序列长度的关系 4&#…...

从GPT入门,到R语言基础与作图、回归模型分析、混合效应模型、多元统计分析及结构方程模型、Meta分析、随机森林模型及贝叶斯回归分析综合应用等专题及实战案例

目录 专题一 GPT及大语言模型简介及使用入门 专题二 GPT与R语言基础与作图&#xff08;ggplot2&#xff09; 专题三 GPT与R语言回归模型&#xff08;lm&glm&#xff09; 专题四 GPT与混合效应模型&#xff08;lmm&glmm&#xff09; 专题五 GPT与多元统计分析&…...

【Android】数据安全(一) —— Sqlite加密

目录 SQLCipherSQLiteCrypt其它 SQLCipher SQLCipher 是 SQLite 数据库的的开源扩展&#xff0c;使用了 256 位 AES 加密&#xff0c;支持跨平台、零配置、数据100%加密、加密开销低至 5 -15%、占用空间小、性能出色等优点&#xff0c;因此非常适合保护嵌入式应用程序数据库&a…...

云原生周刊:Helm Charts 深入探究 | 2024.3.11

开源项目推荐 Glasskube Glasskube 提供了一个用于 Kubernetes 的缺失的包管理器。它具有图形用户界面(GUI)和命令行界面(CLI)。Glasskube 包是具备依赖感知、GitOps 准备和可以通过中央公共包仓库自动更新的特性。 imgpkg imgpkg&#xff08;发音为&#xff1a;"imag…...

【C++初阶】第六站 : 模板初阶

前言&#xff1a; 本章知识点&#xff1a;泛型编程、函数模板、类模板 专栏&#xff1a; C初阶 目录 泛型编程 函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 4.函数模板的实例化 5.模板参数的匹配原则 类模板 类模板的定义格式 类模板的实例化 泛型编程 如何实现一…...

训练保存模型checkpoint时报错SyntaxError: invalid syntax

在使用pytorch训练保存checkpoint时&#xff0c;出现如下报错&#xff1a; rootautodl-container-745411b452-c5cebfed:~/kvasir-seg-main# python train_transunet.py --loss_function"IoULoss" --training_augmentation0File "train_transunet.py", lin…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...