例如下面的代码:

class StrPtr{
public:
StrPtr() : _ptr(nullptr){}
//拷贝构造函数等省略...
std::string* operator->()
{
return _ptr;
}
private:
std::string *_ptr;
};

std::string* operator->()
/*
这句代码的格式不是类似于前导运算符吗?类似于std::string operator*(){//...}不正是*ptr?但是重载的->运算符却是ptr->这样使用的,请问是为什么?
而且std::string* operator->()返回的是指针,为什么可以直接在后面访问类成员,[比如说ptr->size()]?
我的疑问是这是如何实现的,这和我对运算符重载的直接理解有所差异。
*/

解答:

这句代码的格式不是类似于前导运算符吗?类似于std::string operator*(){//...}不正是*ptr?但是重载的->运算符却是ptr->这样使用的,请问是为什么?

因为运算符的结合律不同,dereference operator(*)是 right associative 的,而 member access operator(.->)是 left associative 的。这是不同符号的结合律不同的例子,C++ 里符号相同的时候也会有用法不同导致结合律不同的例子。例如:

 operator | left associative            | right associative
| lhs op rhs / lhs op | op rhs
----------+-----------------------------+---------------------------
++ -- | postfix increment/decrement | prefix increment/decrement
+ - | binary add/subtract | unary plus/minus
* | binary multiply | dereference
& | bitwise and | address-of
() | function call | type conversion

当你重载一个左结合律的操作符时(如+ - * / ()等),往往这个操作符是个二元操作符,对于lhs op rhs,就会调用lhs.operator op(rhs)operator op(lhs, rhs),我们只需要按照这个函数签名来重载操作符就行了。

但是,如果这个操作符是一元操作符怎么办?这就要分情况讨论了:

  • 如果这个符号有一种以上的用法(比如++--),对于lhs op(左结合)和op rhs(右结合),我们得想个办法区分不同的用法啊,所以就会出现用于占位的函数参数(int):

    • 对于lhs op调用lhs.operator op(int)

    • 对于op rhs调用rhs.operator op()

  • 如果这个符号只有一种用法(比如->),对于lhs op,那就不需要用于占位的函数参数了,可以直接写成类似右结合的函数签名,即

    • 对于lhs op调用lhs.operator op()

所以会让人有点糊涂为啥函数签名差不多,用法却不同。

而且std::string* operator->()返回的是指针,为什么可以直接在后面访问类成员,[比如说ptr->size()]?

这是由 C++ 标准规定的,对于ptr->mem根据ptr类型的不同,操作符->的解释也不同:

  • ptr的类型是内置指针类型时,等价于(*ptr).mem

  • ptr的类型是类时,等价于ptr.operator->()->mem

你会发现这是一个递归的解释,对于ptr->mem会递归成:

(*(ptr.operator->().operator->().….operator->())).mem

操作符->是一元的,而操作符.是二元的。操作符->最终是通过操作符.来访问成员的,而.这个操作符是不允许重载的,只能由编译器实现。

举个例子,使用题主定义的类StrPtr

string s = "abc";
StrPtr ptr(&s);
string *sp = &s; ptr->size();
// 等价于 ptr.operator->()->size();
// 等价于 _ptr->size(); 这跟 sp->size(); 不就一样了吗
// 等价于 (*_ptr).size(); 这跟 (*sp).size(); 不就一样了吗

最后一句题外话,C++ 变量名不要用下划线作为起始,用下划线做起始是保留给编译器使用的。可以使用m_somemembersomemember_作为私有成员名称。

 

智能指针中C++重载'->'符号是怎么实现的的更多相关文章

  1. 智能指针的->和 * 重载

  2. 标准库中的智能指针shared_ptr

    智能指针的出现是为了能够更加方便的解决动态内存的管理问题.注:曾经记得有本书上说可以通过vector来实现动态分配的内存的自动管理,但是经过试验,在gcc4.8.5下是不行的.这个是容易理解的,vec ...

  3. C++中的四个智能指针

    只能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象.智能指针定义在memory头文件中. 1. auto_ptr(C++11已经舍弃) 由new expression获得的对象,在au ...

  4. C++的智能指针你了解吗?

  5. Android结构分析Android智能指针(两)

    笔者:刘蒿羽 博客:http://blog.csdn.net/liuhaoyutz Android版本号:4.4.2 在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指 ...

  6. c++ 智能指针(转)

    智能指针的使用 智能指针是在 <memory> 标头文件中的 std 命名空间中定义的. 它们对 RAII 或“获取资源即初始化”编程惯用法至关重要. 此习惯用法的主要目的是确保资源获取与 ...

  7. C11内存管理之道:智能指针

    1.shared_ptr共享智能指针 std::shared_ptr使用引用计数,每个shared_ptr的拷贝都指向相同的内存,在最后一个shared_ptr析构的时候,内存才会释放. 1.1 基本 ...

  8. c++智能指针使用笔记

    1. c++智能指针中,c++的memory文件中,有auto_ptr等各种关于智能指针的东西,shared_ptr,weak_ptr在C++11中已经成为标准. 也看了ogs的智能指针,每次引用起来 ...

  9. 第21课 shared_ptr共享型智能指针

    一. shared_ptr的基本用法 (一)与unique_ptr的比较 比较 shared_ptr unique_ptr 备注 初始化 ①shared_ptr<T> sp; sp.res ...

随机推荐

  1. Oracle之查询排序

    SQL排序查询 DESC降序.ASC升序(默认是升序) /* 语法结构: SELECT * | 列名1[,列名2...] | 表达式 FROM 表名 [WHERE 限定条件] ORDER BY 列名1 ...

  2. Oracle数据库的下载、安装与卸载

    Oracle数据库下载: 这里以Oracle 11g为例,推荐去Oracle官网下载 Oracle官网下载地址:https://www.oracle.com/database/technologies ...

  3. 初识html及网络爬虫概念

    网络爬虫 HTML超文本标记语言 HTTP协议 简单的网络请求 python模块模拟浏览器发送请求 爬虫小案例 爬虫简介 我们一般情况 都是通过浏览器正常访问服务端获取资源浏览器展示给用户看 爬虫 模 ...

  4. 如何从头到脚彻底解决一个MySQL Bug

    摘要:为了保障华为云GaussDB产品的可靠性,每一款产品发布前都要通过多轮严苛的测试用例. 说明:本文中的MySQL,如果不做特殊说明,指的是开源社区版MySQL. 华为云数据库新版本在发布之前,会 ...

  5. PHP pdf转png windows版本

    链接:https://pan.baidu.com/s/1Bli-2HkucRTYTeujkcsmjg&shfl=sharepset 提取码:2une 1.php_imagick扩展 (1)下载 ...

  6. 微信小程序实现简单的2048

    这两天心血来潮,用微信小程序写了一个简单的2048,欢迎各位老铁围观,提出宝贵意见.这里我从0到1赘述一下个人实现流程: 首先去微信公平台(https://mp.weixin.qq.com/)注册一个 ...

  7. golang 中 channel 的详细使用、使用注意事项及死锁分析

    目录 1.什么是 channel,介绍管道 2.channel 的基本使用 3.channel 的使用场景 4.使用 channel的注意事项及死锁分析 什么是 channel 管道 它是一个数据管道 ...

  8. Open Babel的安装与使用

    技术背景 Open Babel是化学领域常用的一个文件格式转换工具,它可以支持xyz的坐标格式.SMILES表达式.InChI表达式和mol以及mol2等格式之间的互相转化.比如说,你只有一个甲烷的S ...

  9. 原生 JS 实现 HTML 转 Markdown,以及其实现逻辑

    之前因为一些需要,需要转换部分 HTML 标签成 markdown 格式,但是不知不觉就完善到一个相对完整的函数. 然后我就封装成了一个文件放在了 github ,也简单做了两个示例网页. HTML ...

  10. jdbc创建数据库的连接

    package com.gylhaut.db; import java.sql.Connection;import java.sql.DriverManager;import java.sql.Res ...