C++ QT中Q_Q和Q_D是什么?怎么使用?本质是什么?C++仿写

devtools/2025/1/19 12:39:22/

1.QT中Q_Q和Q_D是什么?

  • Q_Q可以得到外部可以访问的类指针
  • Q_D可以得到内部封装,外部不可达的类指针

2. 怎么使用?

上代码

  • APrivate.h
#pragma once
#include <QtCore>class A;class APrivate
{Q_DECLARE_PUBLIC(A)
public:APrivate();~APrivate();
public:void APrivateUseA();
private:friend A;A* q_ptr;int m_iA;
};
  • A.h
#pragma once
#include <QtCore>
class APrivate;class A
{Q_DECLARE_PRIVATE(A)
public:A();~A();public://对外接口void setValue(int& iValue);int getValue();public:void APrivateCanUse();void APrivateUse();private:APrivate* d_ptr;
};
  • A.cpp
#include "APrivate.h"
#include "A.h"
#include <iostream>A::A():d_ptr(new APrivate) 
{d_ptr->q_ptr = this;std::cout << "A()" << std::endl;
}
A::~A() 
{Q_D(A);delete d;std::cout << "~A()" << std::endl;
}void A::setValue(int& iValue)
{Q_D(A);d->m_iA = iValue;
}int A::getValue()
{Q_D(A);return d->m_iA;
}void A::APrivateCanUse()
{int iValue = 3;setValue(iValue);
}void A::APrivateUse()
{Q_D(A);d->APrivateUseA();
}APrivate::APrivate():m_iA(1)
{std::cout << "APrivate()" << std::endl;
}
APrivate::~APrivate() 
{std::cout << "~APrivate()" << std::endl;
}void APrivate::APrivateUseA()
{Q_Q(A);q->APrivateCanUse();
}
  • main.cpp使用
#include <QtCore/QCoreApplication>
#include <iostream>
#include "A.h"
#include "APrivate.h"
#include <memory>int main(int argc, char* argv[])
{QCoreApplication a(argc, argv);{	//1std::unique_ptr<A> Aa = std::make_unique<A>();std::cout << Aa->getValue() << std::endl;//2int Value = 2;Aa->setValue(Value);std::cout << Aa->getValue() << std::endl;//3Aa->APrivateUse();std::cout << Aa->getValue() << std::endl;}return a.exec();
}

输出:

APrivate()
A()
1
2
3
~APrivate()
~A()

3.本质是什么?

  • 详见QtCore文件夹下文的头文件qglobal.h
  • 摘录主要部分如下:
template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); }// The body must be a statement:
#define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP
#define Q_DECLARE_PRIVATE(Class) \inline Class##Private* d_func() \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \inline const Class##Private* d_func() const \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \friend class Class##Private;#define Q_DECLARE_PRIVATE_D(Dptr, Class) \inline Class##Private* d_func() \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \inline const Class##Private* d_func() const \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \friend class Class##Private;#define Q_DECLARE_PUBLIC(Class)                                    \inline Class* q_func() { return static_cast<Class *>(q_ptr); } \inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \friend class Class;#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
  • 为了方便理解裁剪代码如下:(对照步骤2如何使用来理解)
template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
//A.h中的声明,Class为A
#define Q_DECLARE_PRIVATE(Class) \inline Class##Private* d_func() \{return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \inline const Class##Private* d_func() const \{return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));} \friend class Class##Private;
//APrivate.h中的声明,Class为A
#define Q_DECLARE_PUBLIC(Class)                                    \inline Class* q_func() { return static_cast<Class *>(q_ptr); } \inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \friend class Class;
//使用时的声明,取得临时指针
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

评论:

优:风格统一,使用便捷

劣:每次使用都要两个指针2*8=16个字节的额外开销

4.仿写

不用QT库,C++仿写

  • BPrivate.h
#pragma once
class B;class BPrivate
{
public:BPrivate();~BPrivate();
public:void BPrivateUseB();
private:friend B;B* q_ptr;int m_iA;
};
  • B.h
#pragma once
class BPrivate;class B
{
public:B();~B();public://对外接口void setValue(int& iValue);int getValue();public:void BPrivateCanUse();void BPrivateUse();private:BPrivate* d_ptr;
};
  • B.cpp
#include "BPrivate.h"
#include "B.h"
#include <iostream>B::B() :d_ptr(new BPrivate)
{d_ptr->q_ptr = this;std::cout << "B()" << std::endl;
}
B::~B()
{delete d_ptr;std::cout << "~B()" << std::endl;
}void B::setValue(int& iValue)
{d_ptr->m_iA = iValue;
}int B::getValue()
{return d_ptr->m_iA;
}void B::BPrivateCanUse()
{int iValue = 3;setValue(iValue);
}void B::BPrivateUse()
{d_ptr->BPrivateUseB();
}BPrivate::BPrivate() :m_iA(1)
{std::cout << "BPrivate()" << std::endl;
}
BPrivate::~BPrivate()
{std::cout << "~BPrivate()" << std::endl;
}void BPrivate::BPrivateUseB()
{q_ptr->BPrivateCanUse();
}
  • main.cpp
#include <QtCore/QCoreApplication>
#include <iostream>
#include "A.h"
#include "APrivate.h"
#include "B.h"
#include "BPrivate.h"
#include <memory>int main(int argc, char* argv[])
{QCoreApplication a(argc, argv);{	//1std::unique_ptr<A> Aa = std::make_unique<A>();std::cout << Aa->getValue() << std::endl;//2int Value = 2;Aa->setValue(Value);std::cout << Aa->getValue() << std::endl;//3Aa->APrivateUse();std::cout << Aa->getValue() << std::endl;}{//1std::unique_ptr<B> Bb = std::make_unique<B>();std::cout << Bb->getValue() << std::endl;//2int Value = 2;Bb->setValue(Value);std::cout << Bb->getValue() << std::endl;//3Bb->BPrivateUse();std::cout << Bb->getValue() << std::endl;}return a.exec();
}
  • 输出(一样):
APrivate()
A()
1
2
3
~APrivate()
~A()
BPrivate()
B()
1
2
3
~BPrivate()
~B()


http://www.ppmy.cn/devtools/151810.html

相关文章

迅为RK3568开发板篇OpenHarmony实操HDF驱动控制LED-编写内核 LED HDF 驱动程序

接下来编译 LED 驱动&#xff0c;该驱动用于在基于华为设备框架&#xff08;HDF&#xff09;的系统中控制 LED 灯的开关&#xff0c;完整代码如下所示&#xff1a; 更多内容可以关注&#xff1a;迅为RK3568开发板篇OpenHarmony

挖掘机检测数据集,准确识别率91.0%,4327张原始图片,支持YOLO,COCO JSON,PASICAL VOC XML等多种格式标注

挖掘机检测数据集&#xff0c;准确识别率91.0%&#xff0c;4327张图片&#xff0c;支持YOLO&#xff0c;COCO JSON&#xff0c;PASICAL VOC XML等多种格式标注 数据集详情 数据集分割 训练组70&#xff05; 3022图片 有效集20&#xff05; 870图片 测试集10&…

vim练级攻略(精简版)

vim推荐配置: curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh 0. 规定 Ctrl-λ 等价于 <C-λ> :command 等价于 :command <回车> n 等价于 数字 blank字符 等价于 空格&#xff0c;tab&am…

Wi-Fi 7、Wi-Fi 6 与 5G、4G 的全方位对比

随着无线通信技术的飞速发展&#xff0c;Wi-Fi 7、Wi-Fi 6&#xff0c;以及5G、4G 已经成为人们生活和工作中不可或缺的网络技术。无论是家庭网络、高速移动通信&#xff0c;还是工业物联网&#xff0c;这些技术都在发挥各自的作用。那么&#xff0c;它们之间有什么区别&#x…

电梯系统的UML文档05

Dispatcher 不控制实际的电梯组件&#xff0c;但它在软件系统中是重要的。每一个电梯有一个ispatcher&#xff0c;主要功能是计算电梯的移动方向、移动目的地以及保持门的打开时间。它和系统中除灯控制器以外的几乎所有控制对象交互。 安全装置也是一个环境对象&#xff0c;它…

Android wifi列表中去自身的热点

Android wifi列表中去自身的热点 一、前言 Android wifi列表中能搜索到自身的热点wifi&#xff1f; 正常手机上都不会出现这个问题&#xff1b;可能是系统底层已经做了过滤处理。 现实开发中Android设备的Wifi能搜索到自身热点也可能会存在。 比如基于两个单独的wifi双模组硬…

02UML图(D1_结构图)

目录 学习前言 ---------------------------------- 讲解一&#xff1a;类图 一、类图的组成结构 1. 类(Class) 1.1. 类的成员变量的表示方式 1.2. 类的成员方法的表示方式 2. 接口&#xff08;Interface&#xff09; 3. 包&#xff08;Package&#xff09; 二、UML类…

[Azure] 如何解决个人账号无法直接登录的问题:利用曲线救国方法访问Speech Studio

近期,Azure的一些用户反映,他们在尝试通过个人账号登录Azure Portal时遇到问题,登录失败或无法访问已创建的资源。虽然Azure可能正在进行一些后台改制,导致了这一问题的发生,但用户仍然需要访问和使用一些资源(比如Speech Studio中的服务)。本文将分享一种曲线救国的解决…