C++11&QT复习 (五)

文章目录

    • [**Day6-2 成员访问运算符重载(2025.03.25)**](#Day6-2 成员访问运算符重载(2025.03.25))
    • [**1. 复习**](#1. 复习)
    • [**2. 成员访问运算符重载**](#2. 成员访问运算符重载)
      • [**2.1 箭头运算符 (`->`) 重载**](#2.1 箭头运算符 (->) 重载)
        • [**(1) 语法**](#(1) 语法)
      • [**2.2 解引用运算符 (`*`) 重载**](#2.2 解引用运算符 (*) 重载)
        • [**(1) 语法**](#(1) 语法)
    • [**3. 代码分析**](#3. 代码分析)
      • [**3.1 代码结构**](#3.1 代码结构)
      • [**3.2 代码解析**](#3.2 代码解析)
        • [**(1) `Data` 类**](#(1) Data)
        • [**(2) `SecondLayer` 类**](#(2) SecondLayer)
        • [**(3) `ThirdLayer` 类**](#(3) ThirdLayer)
      • [**3.3 运行 `test()` 方法**](#3.3 运行 test() 方法)
    • [**4. 总结**](#4. 总结)

Day6-2 成员访问运算符重载(2025.03.25)

1. 复习

在上一节中,我们学习了 C++ 中的 输入输出流运算符重载(<<>> 以及 下标运算符 [] 和函数调用运算符 () 的重载。本节我们将重点学习 成员访问运算符(->*)的重载


2. 成员访问运算符重载

C++ 允许用户自定义类的成员访问方式,其中 ->(箭头运算符)和 *(解引用运算符)是最常见的运算符之一。它们通常用于模拟智能指针或多层指针访问。

2.1 箭头运算符 (->) 重载

(1) 语法
cpp 复制代码
class A {
public:
    B* operator->();
};

作用

  • 允许 A 类的对象 像指针一样访问 B 类的成员
  • 典型用途是在 封装指针 的类(如智能指针)中重载 operator->,使得用户无需手动解引用即可访问目标对象的成员。

注意事项:

  1. 返回值必须是一个指针或者引用,否则无法继续访问成员变量或函数。
  2. 如果返回的是对象的引用 ,则可以实现多层 -> 重载。
  3. operator-> 不能改变调用对象自身 ,因此通常 不应该声明为 const 成员函数

2.2 解引用运算符 (*) 重载

(1) 语法
cpp 复制代码
class A {
public:
    B& operator*();
};

作用

  • 允许 A 类的对象 像指针一样进行解引用
  • 常见于智能指针的实现,使 *ptr 直接返回对象的引用,方便访问其成员。

注意事项:

  1. 返回值一般是引用 (如 B&),这样不会产生额外的拷贝。
  2. 适用于 封装指针 的类,如智能指针或代理类。

3. 代码分析

cpp 复制代码
#include <iostream> 
using namespace std;

class Data
{
public:
	Data(int data = 0)
		:_data(data)
	{
		cout << "Data(int data = 0)" << endl;
	}

	~Data()
	{
		cout << "~Data()" << endl; 
	}

	int getData() const
	{
		return _data;
	}
private:
	int _data;
};

class SecondLayer
{
public:
	SecondLayer(Data* pData)
	:_pData(pData)
	{
		cout << "SecondLayer(Data* pData)" << endl;
	}

	//重载 -> 运算符
	Data* operator->()
	{
		return _pData;
	}

	//解引用重载运算符
	Data& operator*()
	{
		return *_pData;
	}


	~SecondLayer()
	{
		cout << "~SecondLayer()" << endl;
		if (_pData)
		{
			delete _pData;
			_pData = nullptr;
		}
	}


private:
	Data* _pData;
};

class ThirdLayer
{
public:
	ThirdLayer(SecondLayer* pSecond)
		:_pSecond(pSecond)
	{
		cout << "ThirdLayer(SecondLayer* pSecond)" << endl;
	}

	//重载 -> 运算符
	SecondLayer& operator->() 
	{
		return *_pSecond;
	}

	~ThirdLayer()
	{
		cout << "~ThirdLayer()" << endl;
		if (_pSecond)
		{
			delete _pSecond;
			_pSecond = nullptr;
		}
	}

private:
	SecondLayer* _pSecond;
};


void test()
{
	/*Data* data = new Data(1);
	SecondLayer* second = new SecondLayer(data);
	ThirdLayer* third = new ThirdLayer(second);*/

	SecondLayer second(new Data(10));//栈对象
	//A类的对象调用B类的成员函数
	/*cout << "&second : " << &second << endl;
	cout << "second.operator->() :" << second.operator->() << endl;*/

	//  重载operator->  
	cout << "second.operator->()->getData() :" << second.operator->()->getData() << endl;
	cout << "second->getData() :" << second->getData() << endl;

	//  重载operator* 
	cout << "(*second).getData()" << (*second).getData() << endl;


	ThirdLayer third(new SecondLayer(new Data(30)));//栈对象
	cout << "third->getData() : " << third->getData() << endl;
	//还原
	cout << "third.operator->().operator->()->getData()" << third.operator->().operator->()->getData();
}

int main(int argc, char** argv)
{
	test();
	test();
	return 0;
}

3.1 代码结构

上面的代码实现了一个 三层封装 的指针代理类,分别是:

  • Data:数据类,包含一个 _data 成员变量。
  • SecondLayer:封装 Data* 指针,并重载 operator->operator*
  • ThirdLayer:封装 SecondLayer* 指针,并重载 operator->

3.2 代码解析

(1) Data
cpp 复制代码
class Data
{
public:
    Data(int data = 0) : _data(data)
    {
        cout << "Data(int data = 0)" << endl;
    }

    ~Data()
    {
        cout << "~Data()" << endl;
    }

    int getData() const
    {
        return _data;
    }
private:
    int _data;
};
  • Data 类封装了一个 int 类型的数据 _data,提供了 getData() 方法用于获取数据值。
  • 构造函数、析构函数用于跟踪对象的创建和销毁。

(2) SecondLayer
cpp 复制代码
class SecondLayer
{
public:
    SecondLayer(Data* pData) : _pData(pData)
    {
        cout << "SecondLayer(Data* pData)" << endl;
    }

    // 重载 -> 运算符
    Data* operator->()
    {
        return _pData;
    }

    // 解引用运算符 *
    Data& operator*()
    {
        return *_pData;
    }

    ~SecondLayer()
    {
        cout << "~SecondLayer()" << endl;
        if (_pData)
        {
            delete _pData;
            _pData = nullptr;
        }
    }

private:
    Data* _pData;
};
  • 封装 Data* 指针,并提供访问 Data 成员的方式
  • operator->() 返回 _pData 指针,使得 SecondLayer 对象 可以像指针一样使用 -> 访问 Data 的方法
  • operator*() 返回 _pData 所指向的 Data 对象的引用,使 *second 直接返回 Data 对象。

示例:

cpp 复制代码
SecondLayer second(new Data(10));
cout << second->getData() << endl;  // 等价于 second.operator->()->getData()
cout << (*second).getData() << endl; // 等价于 second.operator*().getData()

(3) ThirdLayer
cpp 复制代码
class ThirdLayer
{
public:
    ThirdLayer(SecondLayer* pSecond) : _pSecond(pSecond)
    {
        cout << "ThirdLayer(SecondLayer* pSecond)" << endl;
    }

    // 重载 -> 运算符
    SecondLayer& operator->()
    {
        return *_pSecond;
    }

    ~ThirdLayer()
    {
        cout << "~ThirdLayer()" << endl;
        if (_pSecond)
        {
            delete _pSecond;
            _pSecond = nullptr;
        }
    }

private:
    SecondLayer* _pSecond;
};
  • ThirdLayer 封装了 SecondLayer* 指针,并提供 operator->() 使其 可以像 SecondLayer 一样使用 -> 访问 Data 的方法
  • 实现两层 -> 重载 ,使得 ThirdLayer 可以连续访问 Data 成员。

示例:

cpp 复制代码
ThirdLayer third(new SecondLayer(new Data(30)));
cout << third->getData() << endl;  // 等价于 third.operator->().operator->()->getData()

3.3 运行 test() 方法

cpp 复制代码
void test()
{
    SecondLayer second(new Data(10));
    cout << "second->getData() :" << second->getData() << endl;
    cout << "(*second).getData()" << (*second).getData() << endl;

    ThirdLayer third(new SecondLayer(new Data(30)));
    cout << "third->getData() : " << third->getData() << endl;
    cout << "third.operator->().operator->()->getData() : " << third.operator->().operator->()->getData();
}

输出:

复制代码
Data(int data = 0)
SecondLayer(Data* pData)
second->getData() : 10
(*second).getData() : 10
Data(int data = 0)
SecondLayer(Data* pData)
ThirdLayer(SecondLayer* pSecond)
third->getData() : 30
third.operator->().operator->()->getData() : 30
~ThirdLayer()
~SecondLayer()
~Data()
~SecondLayer()
~Data()
  • SecondLayer 允许访问 Data 对象。
  • ThirdLayer 允许访问 SecondLayer,最终可访问 Data
  • 多层指针访问的代理模式生效,并且析构时正确释放了内存。

4. 总结

运算符 作用 适用场景 返回值类型
operator->() 允许对象像指针一样访问成员 智能指针、代理类 指针或引用
operator*() 允许对象像指针一样解引用 智能指针、代理类 引用

关键点:

  1. operator->() 需要返回指针或引用 ,可以连续调用 ->
  2. operator*() 需要返回对象的引用,避免拷贝,提高性能。
  3. 适用于封装指针的类,如智能指针和代理类

本节学习了 成员访问运算符 ->* 的重载 ,掌握它们的用法可以更好地理解 智能指针代理模式

相关推荐
shaoweijava29 分钟前
基于SpringBoot的美食设计网站(源码+数据库)
数据库·spring boot·mysql·mybatis
Joe_Wang533 分钟前
[数据结构]并查集(系统整理版)
数据结构·c++·算法·leetcode·并查集
网络风云1 小时前
Flask(六)数据库与模型操作
数据库·python·flask
Antonio9153 小时前
【Q&A】QT有哪些状态模式的设计?
qt·ui·状态模式
三氧化真3 小时前
使用FastExcel时的单个和批量插入的问题
java·数据库·mybatis
@hdd4 小时前
QScreen 捕获屏幕(截图)
qt·屏幕捕获·qscreen
rqtz4 小时前
【C++指针】搭建起程序与内存深度交互的桥梁(下)
开发语言·c++·指针
小陈的进阶之路4 小时前
数据结构(并查集,图)
数据结构·c++·算法
SNAKEpc121384 小时前
在MFC中使用Qt(三):通过编辑项目文件(.vcxproj)实现Qt的自动化编译流程
c++·qt·mfc
程序猿阿伟5 小时前
《探秘SQL的BETWEEN:解锁数据范围查询的深度奥秘》
大数据·数据库·sql