more effective c++——Item M30 代理类(二)通过代理类识别operator[]的读写操作

在我们的带引用计数的string类中对于operator[]的操作分为cosnt和非const,const对象调用不会修改string对象的值的函数,并假定非const的operator[]调用时会修改string对象的值,因此非const的operator调用时不管实际上有没有修改string对象的值,都需重新拷贝一份string对象。通过代理类延迟对operator[]的操作可以对读写操作进行识别。
以下为添加代理类的String类的部分实现:

#pragma once
#include <cstring>
#include <iostream>

using namespace std;

class String { // class to be used by application developers
public:
    class proxychar
    {
    public:
        proxychar(const int index, String &rhl);
        proxychar &operator= (const proxychar &rhl);
        proxychar &operator= (const char c);
        friend ostream& operator<<(ostream &os, const proxychar &rhl)
        {
            return os << rhl.m_str.value->data[rhl.m_index];
        }
    private:
        String &m_str;
        int m_index;
    };

    String(const char *value = "");
    const proxychar& operator[](int index) const;
    proxychar& operator[](int index);

    friend proxychar;
    String(const char *value = "");
    const proxychar& operator[](int index) const;
    proxychar& operator[](int index);

private:
    // class representing string values
    struct StringValue : public RCObject {
        char *data;
        StringValue(const char *initValue);
        StringValue(const StringValue& rhs);
        void init(const char *initValue);
        ~StringValue();
    };
    RCPtr<StringValue> value;
};


const String::proxychar& String::operator[](int index) const
{
    return String::proxychar(index,const_cast<String &>(*this));
}

String::proxychar& String::operator[](int index)
{
    return String::proxychar(index, *this);
}

String::proxychar::proxychar(const int index, String &rhl):m_str(rhl),m_index(index)
{

}

String::proxychar& String::proxychar::operator = (const proxychar &rhl)
{
    if (m_str.value->isShared())
    {
        m_str.value = new StringValue(m_str.value->data);
    }
    m_str.value->data[m_index] = rhl.m_str.value->data[rhl.m_index];
    return *this;
}

String::proxychar & String::proxychar::operator=(const char c)
{
    if (m_str.value->isShared())
    {
        m_str.value = new StringValue(m_str.value->data);
    }
    m_str.value->data[m_index] = c;
    return *this;
}

在这里,在调用operator[]时,我们不直接返回char,而是返回一个char的代理类的对象,该类持有string类的引用,并且封装了char所需要的大部分操作,然后在对char的操作,比如operator=中对string进行拷贝,在operator<<中直接返回string的下标.

当需要输出String[index]时,String类先返回一个proxychar对象,然后调用proxychar类的operator<<操作符,此时String类不需要进行拷贝。
当需要修改String[index]时,String类先返回一个proxychar对象,然后调用proxychar类的operator=操作符,此时String类判断是否需要进行拷贝,然后进行赋值

但是这个类存在一些缺陷:
1.需要自己实现原始类(这里是char类型)的所有操作,如operator<<操作符,operator=操作符,operator>>,operator&()操作符等
2.由于每次对string进行索引时,都要构建proxychar的临时对象,存在额外的开销
3.在隐式类型转换上,proxy类即使声明了自己的隐式类型转换函数,将proxy转换为其代理的类型,仍然存在很多类型转换的问题,为了避免后续的类型转换错误,一般的做法是直接将构造函数直接声明为explicit。

class TVStation {
public:
TVStation(int channel);
//...
};
void watchTV(const TVStation& station, float hoursToWatch);
watchTV(10, 2.5); // 借助于 int 到 TVStation 的隐式类型转换
Array<int> intArray;
intArray[4] = 10;
watchTV(intArray[4], 2.5);//失败,不可以通过int的代理类转换为TVStation类
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值