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

来源:互联网 发布:打投做数据是什么 编辑:程序博客网 时间:2024/04/26 23:56

在我们的带引用计数的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 developerspublic:    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 0
原创粉丝点击