一、下标运算符的重载

1.概念

如果一个类表示容器,那么要重载下标运算符[],下标运算符必须是成员函数。下表访问运算符通常要有一个const版本和一个非const版本。如果不定义const版本,那么const对象将无法调用下表运算符。非const版本返回对应位置的引用,const版本返回常量对象的引用

2.示例

通过实现一个string类来熟悉下标运算符的重载

string类的整体结构如下

#include <utility>
#include <iostream>
#include <cstring>using namespace std;class mystring
{
friend istream &operator>>(istream &is, mystring &data);
friend ostream &operator<<(ostream &os, const mystring &data);public:mystring();mystring(const char *str);mystring(const mystring &rval);mystring &operator=(const mystring &rval);char &operator[](size_t n);const char &operator[](size_t n) const;size_t size() const;const char *c_str() const;void swap(mystring &t);~mystring();private:char *data_;
};istream &operator>>(istream &is, mystring &data);
ostream &operator<<(ostream &os, const mystring &data);

具体实现如下和测试

#define _GLIBCXX_DEBUG#include "mystring.h"mystring::mystring():data_(new char[1])
{cout<<"mystring()"<<endl;data_[0]='\0';
}mystring::mystring(const char *str):data_(new char[strlen(str)+1])
{cout<<"mystring(const char *str)"<<endl;strcpy(data_, str);
}mystring::mystring(const mystring &rval):data_(new char[rval.size()+1])
{cout<<"mystring(const mystring &t)"<<endl;strcpy(data_, rval.c_str());
}mystring & mystring::operator=(const mystring &rval)
{cout<<"operator=(const mystring &rval)"<<endl;mystring t(rval);this->swap(t);return *this;
}char & mystring::operator[](size_t n)
{cout<<"operator[](size_t n)"<<endl;return data_[n];
}const char & mystring::operator[](size_t n) const
{cout<<"operator[](size_t n) const"<<endl;return data_[n];
}size_t mystring::size() const
{cout<<__func__<<endl;return strlen(data_);
}const char *mystring::c_str() const
{cout<<__func__<<endl;return data_;
}void mystring::swap(mystring &t)
{cout<<__func__<<endl;std::swap(this->data_, t.data_);
}mystring::~mystring()
{cout<<"~mystring()"<<endl;delete data_[];
}istream &operator>>(istream &is, mystring &data)
{cout<<__func__<<endl;is>>data.data_;return is;
}ostream &operator<<(ostream &os, const mystring &data)
{cout<<__func__<<endl;os<<data.data_;return os;
}int main(int argc, char const *argv[])
{mystring t1("1234"), t2("5678");mystring t3=t1;cout<<t2<<t3<<endl;cout<<t2.size()<<endl;t1.swap(t2);cout<<t1<<t2<<endl;mystring t;t=t2;cout<<t<<endl;const mystring t4=t;cout<<t[2]<<t4[1]<<endl;return 0;
}

上述代码中,mystring类实现了两个版本的operator[]

char & mystring::operator[](size_t n)
{cout<<"operator[](size_t n)"<<endl;return data_[n];
}const char & mystring::operator[](size_t n) const
{cout<<"operator[](size_t n) const"<<endl;return data_[n];
}

都返回的是对应位置的元素的引用。表面看起来,这两个函数的函数名相同,形参列表也相同,好像是违背了函数重载的规则,但是实际上这两个函数的形参列表是不同的

因为operator[]是成员函数,,形参列表中都隐式的存在一个指向创建对象的this指针,非const版本的operator[]的this的类型是mystring *const this,所以,非常量的mystring对象可以调用非常量版本的operator[]

而const版本的operator[]的this的类型是const mystring *const this,所以不仅得永远指向创建对象,而且还要求指向的创建对象不能更改,所以只有const mystring的对象可以调用const版本的operator[]

因为二者的this形参类型不同,所以可以重载成功

关于const函数,见博客https://blog.csdn.net/Master_Cui/article/details/106885048

此外,mystring关于operator=的实现使用了swap,而不是将delete原来的对象,然后再重新创建对象

void mystring::swap(mystring &t)
{cout<<__func__<<endl;std::swap(this->data_, t.data_);
}mystring & mystring::operator=(const mystring &rval)
{cout<<"operator=(const mystring &rval)"<<endl;mystring t(rval);this->swap(t);return *this;
}

类不用自定义swap成员,但是如果一个类含有动态分配内存的操作,那么swap可能就是一个优化的手段。上述代码通过自定义swap,只是改变了两个指针的指向对象,而指向的对象并不需要重新分配内存

减少了动态分配内存和销毁指向对象的次数

参考

https://github.com/chenshuo/recipes/blob/master/string/StringTrivial.h

《C++ Primer》

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

C++知识点42——下标运算符[]的重载及string类的实现相关推荐

  1. C++知识点41——运算符的重载概念与分数类实现(下)

    接上篇文章https://blog.csdn.net/Master_Cui/article/details/109515571继续实现分数类和相关运算符的重载 6.自增自减运算符(++ --)的重载 ...

  2. 下标运算符究竟是单目运算符还是双目运算符

    int arr[10] = { 0 }; arr[0] = 6; char str[100] = ""; str[0] = '8'; 凡是接触过编程的所有人都接触过这种写法吧. 学 ...

  3. 重载运算与类型转换——基本概念,输入和输出运算符,算术和关系运算符,赋值运算符,下标运算符,递增和递减运算符,成员访问运算符...

    一.基本概念 重载的运算符时具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.和其他函数一样,重载的运算符也包含返回类型.参数列表以及函数体. 重载运算符函数的参数 ...

  4. 详解C++中的函数调用和下标以及成员访问运算符的重载

    http://www.jb51.net/article/78436.htm 这篇文章主要介绍了详解C++中的函数调用和下标以及成员访问运算符,讲到了这些二元运算符使用的语法及重载,需要的朋友可以参考下 ...

  5. C++中重载下标运算符[]

    1.C++中重载下标运算符[] C++规定,下标运算符[]必须以成员函数的形式进行重载,该重载函数在类中的声明格式如下: 返回值类型 & operator[] (参数列表);// 或者cons ...

  6. C++重载下标运算符

    C++ 规定,下标运算符[ ]必须以成员函数的形式进行重载.该重载函数在类中的声明格式如下: 返回值类型 & operator[ ] (参数); 或者: const 返回值类型 & o ...

  7. C++之操作符重载探究(四):下标运算符重载

    前文:C++之操作符重载探究(三):输出操作符重载 下标运算符[ ]重载   如果一个类的成员是一个数组,我们可以使用下标操作符来访问数组的成员.例如一个类定义如下:   上述代码存在两个问题:(1) ...

  8. 走进C++程序世界------操作符运算、操作符重载、转换运算符、双目元算、+=,-+运算符,比较运算符及下标运算符

    重载,在一个类定义中,可以编写几个同名的方法,但是只要它们的签名参数列表不同,Java就会将它们看做唯一的方法.简单的说,一个类中的方法与另一个方法同名,但是参数表不同,这种方法称之为重载方法 下面关 ...

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

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

最新文章

  1. 【Qt】在Ubuntu16.04中安装QSerialPort模块
  2. WINDOWS2003域控制器禁止U盘
  3. 行业场景智能应用,解锁边缘计算时代新机遇
  4. SAP Spartacus list.component.ts的listData$数据的触发逻辑
  5. Swift数据类型简介(二)
  6. java多属性的map_java - 具有多个参数的MapStruct QualifiedByName - 堆栈内存溢出
  7. 数学 —— 其他 —— 快速求逆平方根
  8. Qt 的udpSocket通信
  9. 计算机考研雷区,考研的五大雷区是什么 如何避免
  10. Ps雅点设计合成大师
  11. linux十大实用工具,10大好用的Linux实用工具推荐
  12. 430单片机实现三人投票表决器_用ATC实现三人表决器.doc
  13. SpringBoot整合定时任务(在线Cron表达式生成器)
  14. 基于PyQT5的图书管理系统(含文档,源码,安装部署简单)
  15. IT 程序员、软件工程师值得考的证书有哪些?有什么证书可以考?
  16. 新广告法违规词敏感词检测软件淘宝违规词检测查询工具软件
  17. python模拟键盘上键和回车_使用Python模拟键盘输入
  18. 微型计算机一个汉字多少字节,一个汉字多少字节(Byte)?
  19. js与html和css的关系
  20. IBM创磁带存储新纪录

热门文章

  1. 微服务(二)hystrix
  2. 好插件让你事半功倍!【资源篇】
  3. mybatis学习笔记(7)-输出映射
  4. 转载:Objective-C中的 instancetype 和 id 关键字
  5. vim 初学简单设置
  6. 转:ASP自动解压RAR文件
  7. np.c_和np.r_用法
  8. 网络攻击与防御技术第三次实验
  9. 一步步学习SPD2010--第十一章节--处理母版页(7)--管理Content Placeholders
  10. ios 分类(Category)