body, table{font-family: 微软雅黑; font-size: 10pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

#include<iostream>
#include<string.h>
using namespace std;
class String
{ //23种设计模式之代理模式
        class charProxy;
        public:
                String():_pstr(new char[2])
                {
                        cout<<"String()"<<endl;
                        initRefcount();
                }
                String(const char *);
                String(const String&);
                String& operator=(const String&);
                ~String()
                {
                        cout<<"~String()"<<endl;
                        decreaseRefcount();
                        if(0==useCount())
                        {
                                delete []_pstr;
                        }
                }
                int useCount()
                {
                        return _pstr[strlen(_pstr)+1];
                }
                charProxy operator[](int index); //区分写操作,这里要返回一个临时对象就不能是一个引用了
                // char& operator[](int idx)const;  //区分读操作,必须加const关键字,不然和前面函数构成重载
        private:
                char* _pstr;
                void initRefcount()
                {
                        _pstr[strlen(_pstr)+1] = 1;
                }
                void increaseRefcount()
                {
                        ++_pstr[strlen(_pstr)+1];
                }
                void decreaseRefcount()
                {
                        --_pstr[strlen(_pstr)+1];
                }
                class charProxy
                {
                        public:  //这些函数一定要是公有
                                charProxy(String& str,int index):_str(str),_index(index)
                                {
                                        cout<<"charProxy(String&,int)"<<endl;
                                }
                                char& operator=(char ch);         //嵌套类里面,也不能返回对象引用;因为嵌套类对象都是临时的
                                operator char()
                                { //类型转换函数,由Charproxy转向char
                                        cout<<"operator char()"<<endl;
                                        return _str._pstr[_index];
                                }
                        private:
                                String& _str;
                                int _index;
                };
                friend ostream& operator<<(ostream&,const String&);
                friend istream& operator>>(istream&,String&);
};
#if 0
//operator[]()不能区分读操作还是写操作
char & String::operator[](int idx)const       //不能区分读写操作,废弃
{
        cout<<"operator [](int)const"<<endl;
        return _pstr[idx];
}
#endif
String::String(const char* tmp)
{
        cout<<"String(const char*)"<<endl;
        _pstr = new char[strlen(tmp)+2];
        strcpy(_pstr,tmp);
        initRefcount();  //引用计数设置为1
}
String::String(const String& lhs)
{
        cout<<"String(const String&)"<<endl;
        _pstr = lhs._pstr;
        increaseRefcount();
}
String& String::operator=(const String& lhs)
{
        cout<<"String& operator=(const String&)"<<endl;
        decreaseRefcount();
        if(0==useCount())
        {
                delete []_pstr;
        }
        _pstr = lhs._pstr; // 浅拷贝
        increaseRefcount();
        return *this; 
}
ostream& operator<<(ostream& os,const String& rhs)
{
        cout<<"ostream& operator<<(ostream& os,const String&)"<<endl;
        os<<rhs._pstr<<endl;
        return os;
}
istream& operator>>(istream& is,String& s)
{
        cout<<"istream& operator>>(istream&,String&)"<<endl;
        is>>s._pstr;
        return is;
}


String::charProxy String::operator[](int index)
{
        cout<<"charProxy operator[](int)"<<endl;
        return charProxy(*this,index);     //返回临时嵌套类对象
}
char& String::charProxy::operator=(char ch)
{
        cout<<"char& operator=(char)"<<endl;
        if(_index>=0&&_index<strlen(_str._pstr))
        {
                if(1==_str.useCount())  //当对象没有共享内存时
                {
                        _str._pstr[_index] = ch;  //修改
                        return _str._pstr[_index];
                }
                else
                {
                        _str.decreaseRefcount();  //有共享内存
                        char* _strtmp = new char[strlen(_str._pstr)+2];
                        strcpy(_strtmp,_str._pstr);
                        _str = _strtmp;  //这里调用了构造函数和赋值构造函数,操作完之后调用析构函数
                        _str[_index] = ch;  //这里再次调动[]重载函数,进行修改
                        _str.initRefcount();
                        return _str._pstr[_index];
                }
        }
}
int main()
{
        String s1("hello,world");
        String s2(s1);
        cout<<"读操作:"<<s1[1]<<endl;
        cout<<s1.useCount()<<endl;
        cout<<"--------------------------"<<endl;
        cout<<"写操作:"<<endl;
        s1[1] = 'm';
        cout<<"--------------------------"<<endl;
        cout<<s1[1]<<endl;
        cout<<s1.useCount()<<endl;
        return 0;
}
//String(const char*)
//String(const String&)
//charProxy operator[](int)
//charProxy(String&,int)
//operator char()
//读操作:e
//2
//--------------------------
//写操作:
//charProxy operator[](int)
//charProxy(String&,int)
//char& operator=(char)
//String(const char*)
//String& operator=(const String&)
//~String()
//charProxy operator[](int)
//charProxy(String&,int)
//char& operator=(char)
//--------------------------
//charProxy operator[](int)
//charProxy(String&,int)
//operator char()
//m
//1
//~String()
//~String()

这里要识别[]操作只能借助嵌套类来底层实现,因为不可能在String类中重写=运算符;所以当遇到[]操作符的时候就转化成CharProxy的对象,必须传引用对其本身操作,在这个类中就可以重写=运算符来区分读和写,因为这里的=我们后面不会再做其他用处只是区分读写;所以这里分三步:
重写[]运算符
先转换为嵌套类对象
重写=,区分s[]和是s[]=
改:
读:
读的时候cout不能输出CharProxy对象,除非重载;采用类型转换比较方便,会根据需要自动转换

operator[],识别读操作和写操作的更多相关文章

  1. (MariaDB/MySQL)MyISAM存储引擎读、写操作的优先级

    MariaDB/MySQL中使用表级锁的存储引擎(例如MyISAM.Aria(MariaDB对MyISAM引擎的改进,前身是MyISAM))在读(select).写操作(insert.delete.u ...

  2. flash多进程写操作

    1 应用场景介绍   硬件条件:使用stm32 MCU   软件条件:协议栈应用   协议栈简单介绍如下:   类似于OSI七层模型,所涉及的协议栈包括应用层,网络层,链路层,物理层,如下图:   在 ...

  3. C#多线程:使用ReaderWriterLock类实现多用户读/单用户写同步

    摘要:C#提供了System.Threading.ReaderWriterLock类以适应多用户读/单用户写的场景.该类可实现以下功能:如果资源未被写操作锁定,那么任何线程都可对该资源进行读操作锁定, ...

  4. 使用ReaderWriterLock类实现多用户读/单用户写同步

    使用ReaderWriterLock类实现多用户读/单用户写同步[1] 2015-03-12 应用程序在访问资源时是进行读操作,写操作相对较少.为解决这一问题,C#提供了System.Threadin ...

  5. HDFS的工作原理(读和写操作)

    工作原理: NameNode和DateNode,NameNode相当于一个管理者,它管理集群内的DataNode,当客户发送请求过来后,NameNode会 根据情况指定存储到哪些DataNode上,而 ...

  6. CI中获取读操作的结果集行数+获取写操作的影响行数

    本质:读操作,用mysql_num_rows函数,写操作用mysql_affected_rows函数 mysql_num_rows() 返回结果集中行的数目.此命令仅对 SELECT 语句有效.要取得 ...

  7. 汇编指令-MRS(读)和MSR(写)指令操作CPSR寄存器和SPSR寄存器使用(1)

    1.MSR和MRS指令介绍 MRS 指令:  对状态寄存器CPSR和SPSR进行读操作.通过读CPSR可以获得当前处理器的工作状态.读SPSR寄存器可以获得进入异常前的处理器状态(因为只有异常模式下有 ...

  8. python中文件的读和写操作

    一.打开文件 data = open("yesterday",encoding="utf-8").read() # python默认的打字符编码是unicode ...

  9. 基于.net EF6 MVC5+WEB Api 的Web系统框架总结(4)-Excel文件读、写操作

    Excel文件读.写可以使用Office自带的库(Microsoft.Office.Interop.Excel),前提是本机须安装office才能运行,且不同的office版本之间可能会有兼容问题.还 ...

随机推荐

  1. https://www.cnblogs.com/skywang12345/category/455711.html

    https://www.cnblogs.com/skywang12345/category/455711.html

  2. cgwin的ssh错误解决办法

    参考博客    http://hi.baidu.com/luckygirl/item/bd00a6d8a05c310d20e25039 方法一(推荐): 修改/etc/passwd文件,在其中加入 s ...

  3. python3_requests模块详解

    1.模块说明 requests是使用Apache2 licensed 许可证的HTTP库. 用python编写. 比urllib2模块更简洁. Request支持HTTP连接保持和连接池,支持使用co ...

  4. Python3.x:selenium获取iframe内嵌页面的源码

    Python3.x:selenium获取iframe内嵌页面的源码 前言 在一些网页中经常会看到ifrmae/frame标签,iframe是嵌入式框架一般用来在已有的页面中嵌入另一个页面,当一个元素在 ...

  5. Oh My Fish! 让你的 Shell 漂亮起来

    安装 Oh My Fish 安装 omf 很简单.你要做的只是在你的 Fish shell 中运行下面的命令. curl -L https://get.oh-my.fish | fish 一旦安装完成 ...

  6. heartbeat-gui

    一.简介gui heartbeat的v2版本将v1中haresources配置文件使用GUI图形配置接口来配置高可用集群.更加便捷,直观. 二.准备条件和资源规划见上文http://www.cnblo ...

  7. LVS-net

    一.LVS基本情况 lvs:Linux Virtual Server,是一种负载均衡集群,其主要是由工作在内核的ipvs与用户空间的命令行工具ipvsadm组成.支持TCP,UDP,AH,EST,AH ...

  8. JDK 中的监控与故障处理工具-05 (jstack)

    jstack : stack trace for java jstack 命令用于生成虚拟机当前时刻的线程快照 (threaddump).线程快照是当前虚拟机中每一条线程正在执行的方法堆栈的集合,生成 ...

  9. php 模拟 asp.net webFrom 按钮提交事件

    由于公司需要php方面的项目开发,php刚刚入门,在写按钮提交过程中,asp.net里的按钮事件更好些.先看下面的代码, <? require_once '../inc/EventHelper. ...

  10. Java循环跳转语句之 break

    生活中,我们经常会因为某些原因中断既定的任务安排.如在参加 10000 米长跑时,才跑了 500 米就由于体力不支,需要退出比赛.在 Java 中,我们可以使用 break 语句退出指定的循环,直接执 ...