C++知识点43——解引用运算符和箭头运算符的重载及智能指针类的实现
一、概念、
在自定义行为类似指针的类时,需要重载*和->。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——解引用运算符和箭头运算符的重载及智能指针类的实现相关推荐
- c语言 点运算符,C语言点运算符和箭头运算符
二元运算符 . 和 -> 常常被称为点运算符(dot operator)和箭头运算符(arrow operator),借助于这两个运算符,可以选择结构或联合中的成员. 例 1 展示了点运算符的左 ...
- C 语言结构体_点运算符( . )和箭头运算符( - )的区别
很多时候,在对结构体进行相应的编码时,时而发现是用点运算符( . ),时而是用箭头运算符( -> ) 那么这两者之间的使用有什么区别吗? 相同点 两者都是二元操作符,而且右边的操作数都是成员的名 ...
- C 语言结构体之点运算符( . )和箭头运算符( - )的区别
很多时候,在对结构体进行相应的编码时,时而发现是用点运算符( . ),时而是用箭头运算符( -> ):那么这两者之间的使用有什么区别么? 相同点:两者都是二元操作符,而且右边的操作数都是成员的名 ...
- c/c++中点运算符“.“和箭头运算符“→“的区别
.和->都是C++成员运算符,主要用于引用类.结构和共用体的成员. A.B:A是对象或者结构体,B是A的成员 A->B:那么A为指针,->用于成员提取,提取A中的成员B即A-> ...
- C++ 智能指针后面 . 与 -> 运算符的一点体会
C和C++中,->运算符和.运算符都与引用类.结构和共用体的成员有关. A.B意味着A是一个实体,是对象或者结构体,B是A的成员.A->B意味着A是一个指针,B是A的成员. //定义一个A ...
- 怎么new一个指针_C++知识点 34:指针运算符重载 -- 智能指针
#define _CRT_SECURE_NO_WARNINGS #include using namespace std; // 平常可能遇到一个问题 class Test { public: Tes ...
- C++知识点34——动态内存与智能指针
一.动态内存 动态内存所在的位置在堆区,由程序员手动分配并手动释放,而不像栈内存由系统分配和自动释放 C++通过new运算符为对象在堆上分配内存空间并返回该对象的地址,并用delete运算符销毁对象并 ...
- C语言基础丨运算符之求字节数运算符和特殊运算符(十)
求字节数运算符 用于计算数据类型所占的字节数(sizeof). 一.sizeof的概念 sizeof是c语言的一种单目操作符,如c语言的其他操作符++.--等.并且它并不是一个函数,sizeof的操作 ...
- 智能指针:-和*运算符重载 + 模板技术 实现智能指针(C++)
智能指针介绍 在C++中,我们都知道在堆区new 开辟的内存,必须通过delete 进行内存释放,不然会形成内存泄漏.有时候我们使用了new 后在 写了很多代码,忘记delete 也是很正常的.那么我 ...
最新文章
- android siri 源码,Android的SIRI 。
- 机器学习(一)梯度下降算法
- Java智能卡 技术_java智能卡APDU学习笔记
- Java项目--俄罗斯方块
- mysql fn_2019 数据库趋势报告,最受欢迎的是 MySQL
- Lucene就是这么简单
- ★LeetCode(371)——两整数之和(JavaScript)
- Qt error: collect2: error: ld returned 1 exit status
- maven 教程入门 maven 配置管理 编译java程序
- 《JS高级程序设计》之三
- fluidsim win7版本_FluidSIM 5|FluidSIM(液压气动仿真软件)下载v5.0中文免费版 附安装教程 - 欧普软件下载...
- TP-LINK TL-WR845N和腾达W311R怎么设置wds桥接
- 《遥感原理与应用》总结—遥感物理基础
- 51单片机学习笔记0 -- 仿真软件安装(Protues8.0)
- 微积分(七)——一元函数积分学
- 18个使用 jQuery 制作的创意网站欣赏
- vs报错:8007000E 内存资源不足,无法完成此操作
- kali虚拟机系统无法联网;apt-get时无法解析域名
- 前端(JavaScript)------字符串
- NRF24L01的多对一通信