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

cpp自学 day2(—>运算符)

#include <iostream> // 用于输入输出,如 std::cout, std::endl
#include <string>   // 图片中包含此头文件,尽管在此示例中未使用// 定义 Entity 类,这是 ScopedPtr 将要管理的类型
class Entity {
public:int x; // Entity 类的一个公共成员变量// Entity 类的默认构造函数Entity() : x(0) { // 初始化 x 为 0std::cout << "Entity 构造" << std::endl;}// Entity 类的析构函数~Entity() {std::cout << "Entity 析构" << std::endl;}// Entity 类的一个公共成员函数void Print() const { // const 表示此函数不会修改对象的状态std::cout << "Hello! x = " << x << std::endl;}
};// 定义 ScopedPtr 类,一个简单的智能指针模拟
class ScopedPtr {
private:Entity* m_Obj; // 内部封装一个裸指针,指向 Entity 对象public:// 构造函数:接受一个 Entity* 裸指针,接管其所有权ScopedPtr(Entity* entity): m_Obj(entity) // 使用成员初始化列表初始化 m_Obj{// 构造函数体为空,因为初始化已在成员初始化列表中完成std::cout << "ScopedPtr 构造,管理地址: " << m_Obj << std::endl;}// 析构函数:当 ScopedPtr 对象销毁时,自动释放其管理的 Entity 对象~ScopedPtr() {if (m_Obj) { // 确保 m_Obj 不是空指针,避免对空指针进行 deletestd::cout << "ScopedPtr 析构,释放地址: " << m_Obj << std::endl;delete m_Obj; // 释放 m_Obj 指向的内存m_Obj = nullptr; // 将指针置空,防止悬空指针}}// 重载 operator->() (箭头运算符)// 作用:允许通过 ScopedPtr 对象像访问指针一样访问 Entity 对象的成员// 返回值:通常返回内部管理的裸指针Entity* operator->() {return m_Obj; // 返回内部存储的 Entity* 裸指针}// 重载 GetObject() 方法,返回内部裸指针Entity* GetObject() { return m_Obj; }// 禁用复制构造函数和复制赋值运算符,以实现独占所有权(类似 std::unique_ptr)// 防止多个 ScopedPtr 共同管理同一块内存,导致重复释放。ScopedPtr(const ScopedPtr&) = delete;ScopedPtr& operator=(const ScopedPtr&) = delete;
};int main() {// 创建一个 ScopedPtr 对象 'entity',它将管理一个新创建的 Entity 对象。// 使用直接初始化语法,这是创建智能指针的推荐方式。ScopedPtr entity(new Entity());// 通过重载的 operator->() 访问 Entity 对象的成员函数 Print()// 编译时,entity->Print() 会被翻译为 (entity.operator->())->Print();entity->Print();// 访问 Entity 对象的成员变量 x (通过 operator->())entity->x = 20; // 修改 x 的值entity->Print(); // 再次打印,确认 x 已被修改// 暂停程序,等待用户输入,以便观察输出和析构过程std::cin.get();// main 函数结束时,'entity' 对象会离开作用域,// 其 ScopedPtr 类的析构函数会自动被调用,从而自动释放它所管理的 Entity 对象,避免内存泄漏。return 0;
}

看着代码学习 

重载->运算符

解析 entityPtr->Print(); 这行代码的执行过程:

  1. 当编译器看到 entityPtr->Print() 时,它知道 entityPtr 是一个 ScopedPtr 类的对象,而不是一个裸指针。
  2. 于是,编译器会寻找 ScopedPtr 类中是否有 operator->() 的重载。
  3. 它找到了你定义的 Entity* operator->() 函数。
  4. 编译器会调用 entityPtr.operator->()
  5. entityPtr.operator->() 执行,并返回 entityPtr 内部存储的那个 Entity* 类型的裸指针(即 m_Obj 的值)。
  6. 然后,编译器会拿这个返回的 Entity* 裸指针,再对其应用 ->Print() 操作,最终调用到 Entity 类的 Print() 函数。

用箭头运算符获取内存中某值的偏移量笔记

  • 目的: 这种技巧主要用于在编译时计算结构体(或类)成员相对于该结构体(或类)起始地址的偏移量。

  • 核心思想: 利用 C/C++ 编译器在处理结构体成员访问时的特性,即编译器在编译阶段就已知结构体的内存布局和成员的相对位置。它不会真的去解引用一个空指针,而是计算成员的偏移量。

  • 语法示例:

    struct Vector3
    {float x, y, z;
    };int main()
    {// 计算 Vector3 结构体中成员 z 的偏移量int offset = (int)(&((Vector3*)nullptr)->z); // 1749396158901.pngstd::cout << offset << std::endl;// ...
    }
    
  • 解析步骤:

    1. (Vector3*)nullptr: 将空指针 nullptr 强制转换为指向 Vector3 类型的指针。
    2. ((Vector3*)nullptr)->z: 使用箭头运算符 -> 访问 Vector3 结构体中的成员 z。此时编译器会根据 Vector3 的定义,确定 z 相对于结构体起始地址的偏移量。
    3. &(...): & 是取地址运算符,它获取的是 z 成员的地址。由于我们是基于 nullptr(地址 0)进行的操作,这个“地址”实际上就是 z 相对于结构体起始的偏移量。
    4. (int): 将计算得到的偏移量(通常是 size_t 类型)强制转换为 int 类型以便打印。

相关文章:

  • unipp---HarmonyOS 应用开发实战
  • PHP环境极速搭建
  • 开源大模型网关:One API实现主流AI模型API的统一管理与分发
  • 工作记录 2018-08-21
  • leetcode189-轮转数组
  • 开源项目实战学习之YOLO11:12.6 ultralytics-models-tiny_encoder.py
  • 学习python做表格6月8日补录
  • 手写 vue 源码 === runtime-core 实现
  • Mysql 基础
  • 第二十七章 位置参数
  • Pinocchio 库详解及其在足式机器人上的应用
  • FPGA静态功耗
  • 【FPGA开发】DDS信号发生器设计
  • 【动态规划】子序列问题(二)
  • Python安装使用教程
  • 国家奖学金答辩PPT+文稿
  • 第三章 内存
  • AUTOSAR实战教程--DoIP_01_配置项解释
  • 在VSCode中使用Ultralytics扩展
  • vscode 配置 latex
  • ps网站轮播图怎么做的/seo快速排名案例
  • 可以做app的网站/长沙百度快照优化排名
  • 青岛专业设计网站公司/新郑网络推广外包
  • 深圳市福田区香蜜湖街道/搜索优化指的是什么
  • 官方在家做兼职的网站/百度浏览器网站入口
  • 网络广告营销概念/优化师和运营区别