一、概念、

在自定义行为类似指针的类时,需要重载*和->。C++中的智能指针就重载了这两个运算符。->必须是成员函数,*也应该是成员函数。与内置类型保持一致,这两个函数通常都是const的。以为*和->通常不会也不应该改变对象的状态

*运算符的返回值通常都是一个类型的引用(因为类内部的数据不一定非得指向T的对象,也可能指向一个T的派生类对象。如果是这样并且operator*返回的是个T对象,而非一个引用(代表真正的派生类对象),那么,operator*函数便是返回一个错误类型的对象!,也就是导致子类对象转基类对象的切割问题)

->运算符的返回值必须是一个类的指针。因为当自定义类型的operator->被调用时,编译器会将operator->转化为

(obejct.operator->())->member

所以,operator->的返回值必须是一个指针

二、示例

通过实现一个智能指针来熟悉这两个运算符的重载,类的整体实现如下

#include <iostream>
#include <memory>using namespace std;template <typename T>
class mysmartpointer
{
public:mysmartpointer(T *ptr=nullptr):ptr_(ptr),pcount_(new size_t(0)){cout<<__func__<<endl;if (ptr_==nullptr) {//空指针不增加引用计数*(this->pcount_)=0;}else {*(this->pcount_)=1;}}mysmartpointer(const mysmartpointer &rval):ptr_(rval.ptr_),pcount_(rval.pcount_){if (ptr_) {//拷贝初始化,如果指针不为空,增加引用计数++*pcount_;}cout<<"mysmartpointer(const mysmartpointer &rval)"<<endl;}mysmartpointer &operator=(const mysmartpointer &rval){cout<<__func__<<endl;mysmartpointer t(rval);this->swap(t);--*pcount_;//减少左值的引用计数if (*pcount_==0) {//此时如果引用计数为0,那么释放指向的对象和引用计数cout<<"delete object when operator="<<endl;delete ptr_;delete pcount_;}++*rval.pcount_;//增加右值的引用计数return *this;}T &operator*() const{cout<<__func__<<endl;return *ptr_;//返回指向对象本身}T *operator->() const{cout<<__func__<<endl;return &this->operator*();//通过调用operator*来实现operator->}explicit operator bool(){cout<<__func__<<endl;return !(ptr_==nullptr && *pcount_==0);}void swap(mysmartpointer &t)//交换指针和引用计数{cout<<__func__<<endl;std::swap(this->ptr_, t.ptr_);std::swap(this->pcount_, t.pcount_);}size_t use_count(){cout<<__func__<<endl;return *pcount_;}~mysmartpointer(){cout<<__func__<<endl;if (--*pcount_==0) {//析构时,--引用计数cout<<"delete object"<<endl;delete ptr_;delete pcount_;}}private:T *ptr_;size_t *pcount_;
};

上述代码中,operator->的实现使用过operator*来实现。这两个函数一般只实现一个,另一个直接调用即可

该类中引用计数是采用指针的方式实现的,当对智能指针进行赋值、拷贝时,可以利用指针的特性让两个对象的引用计数同时指向一块内存,共享引用计数

operator=的实现也是采用swap方式,避免重新分配内存,而且可以处理自赋值的情况

测试

int main(int argc, char const *argv[])
{mysmartpointer<string> spstr1(new string("1234"));mysmartpointer<string> spstr2=spstr1;cout<<spstr1.use_count()<<endl;cout<<spstr2.use_count()<<endl;cout<<"------"<<endl;mysmartpointer<string> spstr3;spstr3=spstr1;spstr1=spstr1;cout<<spstr3.use_count()<<endl;cout<<spstr1.use_count()<<endl;cout<<spstr2.use_count()<<endl;cout<<spstr1->size()<<endl;if (spstr1) {cout<<"spstr1 is not nullptr"<<endl;}return 0;
}

参考

《C++ Primer》

《More Effective C++》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++知识点43——解引用运算符和箭头运算符的重载及智能指针类的实现相关推荐

  1. c语言 点运算符,C语言点运算符和箭头运算符

    二元运算符 . 和 -> 常常被称为点运算符(dot operator)和箭头运算符(arrow operator),借助于这两个运算符,可以选择结构或联合中的成员. 例 1 展示了点运算符的左 ...

  2. C 语言结构体_点运算符( . )和箭头运算符( - )的区别

    很多时候,在对结构体进行相应的编码时,时而发现是用点运算符( . ),时而是用箭头运算符( -> ) 那么这两者之间的使用有什么区别吗? 相同点 两者都是二元操作符,而且右边的操作数都是成员的名 ...

  3. C 语言结构体之点运算符( . )和箭头运算符( - )的区别

    很多时候,在对结构体进行相应的编码时,时而发现是用点运算符( . ),时而是用箭头运算符( -> ):那么这两者之间的使用有什么区别么? 相同点:两者都是二元操作符,而且右边的操作数都是成员的名 ...

  4. c/c++中点运算符“.“和箭头运算符“→“的区别

    .和->都是C++成员运算符,主要用于引用类.结构和共用体的成员. A.B:A是对象或者结构体,B是A的成员 A->B:那么A为指针,->用于成员提取,提取A中的成员B即A-> ...

  5. C++ 智能指针后面 . 与 -> 运算符的一点体会

    C和C++中,->运算符和.运算符都与引用类.结构和共用体的成员有关. A.B意味着A是一个实体,是对象或者结构体,B是A的成员.A->B意味着A是一个指针,B是A的成员. //定义一个A ...

  6. 怎么new一个指针_C++知识点 34:指针运算符重载 -- 智能指针

    #define _CRT_SECURE_NO_WARNINGS #include using namespace std; // 平常可能遇到一个问题 class Test { public: Tes ...

  7. C++知识点34——动态内存与智能指针

    一.动态内存 动态内存所在的位置在堆区,由程序员手动分配并手动释放,而不像栈内存由系统分配和自动释放 C++通过new运算符为对象在堆上分配内存空间并返回该对象的地址,并用delete运算符销毁对象并 ...

  8. C语言基础丨运算符之求字节数运算符和特殊运算符(十)

    求字节数运算符 用于计算数据类型所占的字节数(sizeof). 一.sizeof的概念 sizeof是c语言的一种单目操作符,如c语言的其他操作符++.--等.并且它并不是一个函数,sizeof的操作 ...

  9. 智能指针:-和*运算符重载 + 模板技术 实现智能指针(C++)

    智能指针介绍 在C++中,我们都知道在堆区new 开辟的内存,必须通过delete 进行内存释放,不然会形成内存泄漏.有时候我们使用了new 后在 写了很多代码,忘记delete 也是很正常的.那么我 ...

最新文章

  1. android siri 源码,Android的SIRI 。
  2. 机器学习(一)梯度下降算法
  3. Java智能卡 技术_java智能卡APDU学习笔记
  4. Java项目--俄罗斯方块
  5. mysql fn_2019 数据库趋势报告,最受欢迎的是 MySQL
  6. Lucene就是这么简单
  7. ★LeetCode(371)——两整数之和(JavaScript)
  8. Qt error: collect2: error: ld returned 1 exit status
  9. maven 教程入门 maven 配置管理 编译java程序
  10. 《JS高级程序设计》之三
  11. fluidsim win7版本_FluidSIM 5|FluidSIM(液压气动仿真软件)下载v5.0中文免费版 附安装教程 - 欧普软件下载...
  12. TP-LINK TL-WR845N和腾达W311R怎么设置wds桥接
  13. 《遥感原理与应用》总结—遥感物理基础
  14. 51单片机学习笔记0 -- 仿真软件安装(Protues8.0)
  15. 微积分(七)——一元函数积分学
  16. 18个使用 jQuery 制作的创意网站欣赏
  17. vs报错:8007000E 内存资源不足,无法完成此操作
  18. kali虚拟机系统无法联网;apt-get时无法解析域名
  19. 前端(JavaScript)------字符串
  20. NRF24L01的多对一通信

热门文章

  1. Git查看、删除、重命名远程分支和tag【转】
  2. 怎么样MyEclipse配置Tomcat?
  3. 路由器NAT网络地址转换
  4. FineUI小技巧(4)关闭窗体那些事
  5. C/C++基础面试题集锦
  6. IPad开发之有帮助的开发工具
  7. Oracle常用dump命令
  8. 微信小程序实现图书管理系统
  9. 【JVM】JVM系列之JVM体系(一)
  10. textarea 固定大小,滚动条,限制拖动,文字对齐