智能指针中C++重载'->'符号是怎么实现的
例如下面的代码:
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_somemember
或somemember_
作为私有成员名称。
智能指针中C++重载'->'符号是怎么实现的的更多相关文章
- 智能指针的->和 * 重载
- 标准库中的智能指针shared_ptr
智能指针的出现是为了能够更加方便的解决动态内存的管理问题.注:曾经记得有本书上说可以通过vector来实现动态分配的内存的自动管理,但是经过试验,在gcc4.8.5下是不行的.这个是容易理解的,vec ...
- C++中的四个智能指针
只能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象.智能指针定义在memory头文件中. 1. auto_ptr(C++11已经舍弃) 由new expression获得的对象,在au ...
- C++的智能指针你了解吗?
- Android结构分析Android智能指针(两)
笔者:刘蒿羽 博客:http://blog.csdn.net/liuhaoyutz Android版本号:4.4.2 在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指 ...
- c++ 智能指针(转)
智能指针的使用 智能指针是在 <memory> 标头文件中的 std 命名空间中定义的. 它们对 RAII 或“获取资源即初始化”编程惯用法至关重要. 此习惯用法的主要目的是确保资源获取与 ...
- C11内存管理之道:智能指针
1.shared_ptr共享智能指针 std::shared_ptr使用引用计数,每个shared_ptr的拷贝都指向相同的内存,在最后一个shared_ptr析构的时候,内存才会释放. 1.1 基本 ...
- c++智能指针使用笔记
1. c++智能指针中,c++的memory文件中,有auto_ptr等各种关于智能指针的东西,shared_ptr,weak_ptr在C++11中已经成为标准. 也看了ogs的智能指针,每次引用起来 ...
- 第21课 shared_ptr共享型智能指针
一. shared_ptr的基本用法 (一)与unique_ptr的比较 比较 shared_ptr unique_ptr 备注 初始化 ①shared_ptr<T> sp; sp.res ...
随机推荐
- drawable如何修改图片大小
这个问题刚开始遇到是导入图片太大,在网上找了许多教程大多都是采用setBounds()方法自己尝试许多次还是没成功,在经历了多达数个小时折磨后我找到两个方法1.在导入图片之前直接对图片进行修改大小.( ...
- mapreduce 中 groupingComparator 用法
groupingComparator是对reduce输入的数据进行分组,比如 public int compare(WritableComparable a, WritableComparable b ...
- 三、ES6中数组拓展
一.Array.of() 将参数中所有值作为元素形成数组: console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] 参数的值可以为不同的类型: conso ...
- 用WebDev.WebServer40.EXE调试VS代码
1.找到WebDev.WebServer40的录井,一般位于C:/Program Files (x86)/Common Files/Microsoft Shared/DevServer/10.0/We ...
- JZ-050-数组中重复的数字
数组中重复的数字 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中 第一个重复的数字. 例 ...
- windows2008R2重建索引
windows索引服务 索引服务是一项系统服务(Indexing Service),使用文档筛选器读取整个文档,并提取文档和属性传递给索引程序,这个过程称为"索引".索引服务可以从 ...
- Docker——镜像讲解
镜像是什么 镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码.运行时.库.环境变量和配置文件. 所有的应用,直接打包doc ...
- 实践:Linux下安装mysql8.0
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 一.下载mysql8.0安装包 1.在local创建mysql文件夹 cd /usr/local mkdir mysql cd mysql 2.使 ...
- ZYNQ使用ymodem协议传输文件
SDK: V2014.4 协议: Ymodem 工具: USB转UART转接线.xshell6软件 可实现各种文件传输,大小不限,只是速度很慢 参考原代码如下: /****************** ...
- linux 查看命令
linux查找命令 ls查看文件信息 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭 ...