当前位置: 首页 > 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 类型以便打印。

http://www.xdnf.cn/news/939943.html

相关文章:

  • 常见 DOM 事件全解析
  • DAY 48 随机函数与广播机制
  • 模拟 - #介绍 #题解
  • 使用智能表格做需求管理
  • 【本地AI大模型部署+可视化界面图文教程】Ollama+Qwen3
  • 从C到C++语法过度1
  • Ajax入门
  • SAP顾问职位汇总(第23周)
  • ​**​CID字体​**​ 和 ​**​Simple字体​**​
  • Python实例题:Python计算数理统计
  • 大语言模型(LLM)面试问题集
  • beckHoff_FB --> GET SNC 功能块
  • 程序问题实录
  • 模块缝合-把A模块换成B模块(没写完)
  • Spring缓存注解的陷阱:为什么@CacheEvict删不掉Redis缓存?
  • 正常流程、可选流程和异常
  • OPENCV图形计算面积、弧长API讲解(1)
  • 【Linux】文件赋权(指定文件所有者、所属组)、挂载光驱(图文教程)
  • 如何计算1920*1080分辨率的YUV或RGB图像数据占用大小?
  • Cinnamon修改面板小工具图标
  • 分词算法总结:不同分词算法的优点和缺点
  • 【量化】策略交易类型
  • Razor编程RenderXXX相关方法大全
  • 鸿蒙的一些布局
  • 更新积木报表2.0.0注意事项
  • 第八章 信息安全基础知识
  • 大三下第16周总结
  • 华为OD机考-内存冷热标记-多条件排序
  • 4、docker常用命令
  • 前端八股笔记