当前位置: 首页 > 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…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...