也许不可能在operator[]内部区分左值还是右值操作,但我们仍然能区别对待读操作和写操作,如果我们将判断读还是写的行为推迟到我们知道operator[]的结果被怎么使用之后的话。我们所需要的是有一个方法将读或写的判断推迟到operator[]返回之后。
proxy类可以让我们得到我们所需要的时机,因为我们可以修改operator[]让它返回一个(代理字符的)proxy对象而不是字符本身。我们可以等着看这个proxy怎么被使用。如果是读它,我们可以断定operator[]的调用是读。如果它被写,我们必须将operator[]的调用处理为写。
文件String.h
 1 #ifndef _STRING_H
#ifndef _STRING_H
 2 #define _STRING_H
#define _STRING_H
 3
 4 #include <ostream>
#include <ostream>
 5 class String
class String
 6

 {
{
 7 public:
public:
 8 class CharProxy
    class CharProxy
 9
 
     {
{
10 public:
    public:
11
 CharProxy(String& rStr, int nPos):str(rStr), pos(nPos)
        CharProxy(String& rStr, int nPos):str(rStr), pos(nPos) {}
{}
12 CharProxy& operator=(char c)
        CharProxy& operator=(char c)
13
 
         {
{
14 if( str.value->refCount > 1 )
            if( str.value->refCount > 1 )
15
 
             {
{
16 --str.value->refCount;
                 --str.value->refCount;
17 str.value = new StringValue( str.value->data );
                 str.value = new StringValue( str.value->data );
18 }
            }
19 str.value->data[pos] = c;
            str.value->data[pos] = c;
20 return *this;
            return *this;
21 }
        }
22 CharProxy& operator=(const CharProxy& rhs)
        CharProxy& operator=(const CharProxy& rhs)
23
 
         {
{
24 if( str.value->refCount > 1 )
            if( str.value->refCount > 1 )
25
 
             {
{
26 --str.value->refCount;
                 --str.value->refCount;
27 str.value = new StringValue( rhs.str.value->data );
                 str.value = new StringValue( rhs.str.value->data );
28 }
            }
29 str.value->data[pos] = rhs.str.value->data[pos];
            str.value->data[pos] = rhs.str.value->data[pos];
30 return *this;
            return *this;
31 }
        }
32
33 //convert type of CharProxy to type of char to validate code like:char c = str[0]
        //convert type of CharProxy to type of char to validate code like:char c = str[0]
34
 operator char()
        operator char() {return str.value->data[pos]; }
{return str.value->data[pos]; }
35
36 //const version of CharProxy to char conversion;
        //const version of CharProxy to char conversion;
37
 operator const char()const
        operator const char()const {return str.value->data[pos]; }
{return str.value->data[pos]; }
38
39 //convert type of CharProxy to type of char& to validate code like:char& c = str[0];
        //convert type of CharProxy to type of char& to validate code like:char& c = str[0];
40 operator char&()
        operator char&()
41
 
         {
{
42 if( str.value->refCount > 1 )
           if( str.value->refCount > 1 )
43
 
            {
{
44 --str.value->refCount;
                --str.value->refCount;
45 str.value = new StringValue( str.value->data );
                str.value = new StringValue( str.value->data );
46 }
           }
47 str.value->shareable = false;
           str.value->shareable = false;
48 return str.value->data[pos];
           return str.value->data[pos]; 
49 }
        }
50 //const version of conversion of CharProxy to char&;
        //const version of conversion of CharProxy to char&;
51
 operator const char&()const
        operator const char&()const {return str.value->data[pos]; }
{return str.value->data[pos]; }
52 
        
53 //overload operator ampersand(&) to validate code like:char* p = &str[0];
        //overload operator ampersand(&) to validate code like:char* p = &str[0];
54 char* operator&()
        char* operator&()
55
 
         {
{
56 if( str.value->refCount > 1 )
           if( str.value->refCount > 1 )
57
 
            {
{
58 --str.value->refCount;
                --str.value->refCount;
59 str.value = new StringValue( str.value->data );
                str.value = new StringValue( str.value->data );
60 }
           }
61 str.value->shareable = false;
           str.value->shareable = false;
62 return &str.value->data[pos];
           return &str.value->data[pos]; 
63 }
        }
64 //const version of operator ampersand(&) overloading;
        //const version of operator ampersand(&) overloading;
65
 const char* operator&()const
        const char* operator&()const { return &str.value->data[pos];}
{ return &str.value->data[pos];}
66
67 private:
    private:
68 String& str;
        String& str;
69 int pos;
        int pos;
70 };
    };
71
72 String(const char* cszStr = "");
    String(const char* cszStr = "");
73 String(const String& rhs);
    String(const String& rhs);
74 String& operator=(const String& rhs);
    String& operator=(const String& rhs);
75 ~String();
    ~String();
76
 const char* c_str()const
    const char* c_str()const {return value->data;}
{return value->data;}
77
78 public:
public:
79 CharProxy operator[](size_t idx);
    CharProxy operator[](size_t idx);
80 const CharProxy operator[](size_t idx)const;
    const CharProxy operator[](size_t idx)const;
81
82 public:
public:
83 struct StringValue
    struct StringValue
84
 
     {
{
85 size_t refCount;
        size_t refCount;
86 size_t len;
        size_t len;
87 bool shareable;
        bool shareable;
88 char* data;
        char* data;
89 
    
90 StringValue(const char* cszStr);
        StringValue(const char* cszStr);
91 ~StringValue();
        ~StringValue();
92 };
    };
93
94 private:
private:
95 StringValue* value;
    StringValue* value;
96 };
};
97 #endif
#endif
98
 
文件String.cpp
 1 #include "String.h"
#include "String.h"
 2 #include <string.h>
#include <string.h>
 3 #include <assert.h>
#include <assert.h>
 4
 5 String::String(const char* cszStr)
String::String(const char* cszStr)
 6

 {
{             
 7 value = new StringValue(cszStr);
    value = new StringValue(cszStr);
 8 }
}
 9
10 String::String(const String& rhs)
String::String(const String& rhs)
11

 {
{
12 if( rhs.value->shareable )
    if( rhs.value->shareable )
13
 
     {
{                
14 value = rhs.value;
       value = rhs.value;
15 value->refCount++;
       value->refCount++;
16 }
    }
17 else
    else
18
 
     {
{
19 value = new StringValue(rhs.value->data);
        value = new StringValue(rhs.value->data);
20 }
    }
21 }
}
22
23 String& String::operator=(const String& rhs)
String& String::operator=(const String& rhs)
24

 {
{
25 if( rhs.value == value )return *this;
    if( rhs.value == value )return *this;
26
27 if( rhs.value->shareable )
    if( rhs.value->shareable )
28
 
     {
{
29 --value->refCount;
        --value->refCount;
30 if( value->refCount == 0 )delete value;
        if( value->refCount == 0 )delete value;
31 
        
32 value = rhs.value;
        value = rhs.value;
33 ++value->refCount;
        ++value->refCount;
34 }
     }
35 else
     else
36
 
      {
{
37 value = new StringValue(rhs.value->data);
         value = new StringValue(rhs.value->data);
38 }
     }
39 return *this;
    return *this;
40 }
}
41
42 String::~String()
String::~String()
43

 {
{
44 if( --value->refCount == 0 )delete value;
    if( --value->refCount == 0 )delete value;
45 }
}
46
47 String::CharProxy String::operator[](size_t idx)
String::CharProxy String::operator[](size_t idx)
48

 {
{
49 assert( idx < value->len && idx >= 0);
    assert( idx < value->len && idx >= 0);
50 return  String::CharProxy(*this, idx );
    return  String::CharProxy(*this, idx );    
51 }
}
52 const String::CharProxy String::operator[](size_t idx)const
const String::CharProxy String::operator[](size_t idx)const
53

 {
{
54 assert( idx < value->len && idx >= 0);
    assert( idx < value->len && idx >= 0);
55 return CharProxy(const_cast<String&>(*this), idx );
    return CharProxy(const_cast<String&>(*this), idx );
56 }
}
57
58 String::StringValue::StringValue(const char* cszStr)
String::StringValue::StringValue(const char* cszStr)
59 :refCount(1),shareable(true)
    :refCount(1),shareable(true)
60

 {
{
61 len = strlen(cszStr);
    len = strlen(cszStr);
62 data = new char[len + 1];
    data = new char[len + 1];
63 if( len == 0 )data[0] = '\0';
    if( len == 0 )data[0] = '\0';
64 else strcpy(data, cszStr);
    else strcpy(data, cszStr);
65 }
}
66
67 String::StringValue::~StringValue()
String::StringValue::~StringValue()
68

 {
{
69 delete[] data;
    delete[] data;
70 data = 0;
    data = 0;
71 }
}
72
 
测试程序
 1 #include <iostream>
#include <iostream>
 2 #include "String.h"
#include "String.h"
 3
 4 using namespace std;
using namespace std;
 5
 6 std::ostream& operator<< (std::ostream& os, String& str)
std::ostream& operator<< (std::ostream& os, String& str)
 7

 {
{
 8 os << str.c_str();
    os << str.c_str();
 9 return os;
    return os;
10 }
}
11 int main()
int main()
12

 {
{
13 String str1 = "hello";
    String str1 = "hello";
14 String str2(str1);
    String str2(str1);
15
16 cout << "------initial status------" << endl;
    cout << "------initial status------" << endl;
17
18 cout << "\tstr1 = " << str1 << endl;
    cout << "\tstr1 = " << str1 << endl;
19 cout << "\tstr2 = " << str2 << endl;
    cout << "\tstr2 = " << str2 << endl;
20 printf( "\tstr1 address:%p\n", str1.c_str());
    printf( "\tstr1 address:%p\n", str1.c_str());
21 printf( "\tstr2 address:%p\n", str2.c_str());
    printf( "\tstr2 address:%p\n", str2.c_str());
22 cout << endl;
    cout << endl;
23
24
25 cout << "------after reading str1[0]------" << endl;
    cout << "------after reading str1[0]------" << endl;
26 str1[0];
    str1[0];
27 cout << "\tstr1 = " << str1 << endl;
    cout << "\tstr1 = " << str1 << endl;
28 cout << "\tstr2 = " << str2 << endl;
    cout << "\tstr2 = " << str2 << endl;
29 printf( "\tstr1 address:%p\n", str1.c_str());
    printf( "\tstr1 address:%p\n", str1.c_str());
30 printf( "\tstr2 address:%p\n", str2.c_str());
    printf( "\tstr2 address:%p\n", str2.c_str());
31 cout << endl;
    cout << endl;
32
33 cout << "------after writing str1[0]------" << endl;
    cout << "------after writing str1[0]------" << endl;
34 str1[0] = 'X';
    str1[0] = 'X';
35 cout << "\tstr1 = " << str1 << endl;
    cout << "\tstr1 = " << str1 << endl;
36 cout << "\tstr2 = " << str2 << endl;
    cout << "\tstr2 = " << str2 << endl;
37 printf( "\tstr1 address:%p\n", str1.c_str());
    printf( "\tstr1 address:%p\n", str1.c_str());
38 printf( "\tstr2 address:%p\n", str2.c_str());
    printf( "\tstr2 address:%p\n", str2.c_str());
39 cout << endl;
    cout << endl;
40
41 cout << "str1 = " << str1 << endl;
    cout << "str1 = " << str1 << endl;
42 char& c = str1[1];
    char& c = str1[1];
43 c = 'Y';
    c = 'Y';
44 cout << "str1 = " << str1 << endl;
    cout << "str1 = " << str1 << endl;
45
46 const char& d = str1[1];
    const char& d = str1[1];
47 cout << "the 2nd character is:" << d << endl;
    cout << "the 2nd character is:" << d << endl;
48
49 char* p = &str1[1];
    char* p = &str1[1];
50 *p = 'X';
    *p = 'X';
51 cout << "str1 = " << str1 << endl;
    cout << "str1 = " << str1 << endl;
52
53 const char* q = &str1[1];
    const char* q = &str1[1];
54 cout << "the 2nd character is:" << *q << endl;
    cout << "the 2nd character is:" << *q << endl;
55 
    
56 system("PAUSE");
    system("PAUSE");
57 return EXIT_SUCCESS;
    return EXIT_SUCCESS;
58 }
}
59