也许不可能在operator[]内部区分左值还是右值操作,但我们仍然能区别对待读操作和写操作,如果我们将判断读还是写的行为推迟到我们知道operator[]的结果被怎么使用之后的话。我们所需要的是有一个方法将读或写的判断推迟到operator[]返回之后。
proxy类可以让我们得到我们所需要的时机,因为我们可以修改operator[]让它返回一个(代理字符的)proxy对象而不是字符本身。我们可以等着看这个proxy怎么被使用。如果是读它,我们可以断定operator[]的调用是读。如果它被写,我们必须将operator[]的调用处理为写。
文件String.h
1#ifndef _STRING_H
2#define _STRING_H
3
4#include <ostream>
5class String
6{
7public:
8 class CharProxy
9 {
10 public:
11 CharProxy(String& rStr, int nPos):str(rStr), pos(nPos){}
12 CharProxy& operator=(char c)
13 {
14 if( str.value->refCount > 1 )
15 {
16 --str.value->refCount;
17 str.value = new StringValue( str.value->data );
18 }
19 str.value->data[pos] = c;
20 return *this;
21 }
22 CharProxy& operator=(const CharProxy& rhs)
23 {
24 if( str.value->refCount > 1 )
25 {
26 --str.value->refCount;
27 str.value = new StringValue( rhs.str.value->data );
28 }
29 str.value->data[pos] = rhs.str.value->data[pos];
30 return *this;
31 }
32
33 //convert type of CharProxy to type of char to validate code like:char c = str[0]
34 operator char(){return str.value->data[pos]; }
35
36 //const version of CharProxy to char conversion;
37 operator const char()const{return str.value->data[pos]; }
38
39 //convert type of CharProxy to type of char& to validate code like:char& c = str[0];
40 operator char&()
41 {
42 if( str.value->refCount > 1 )
43 {
44 --str.value->refCount;
45 str.value = new StringValue( str.value->data );
46 }
47 str.value->shareable = false;
48 return str.value->data[pos];
49 }
50 //const version of conversion of CharProxy to char&;
51 operator const char&()const{return str.value->data[pos]; }
52
53 //overload operator ampersand(&) to validate code like:char* p = &str[0];
54 char* operator&()
55 {
56 if( str.value->refCount > 1 )
57 {
58 --str.value->refCount;
59 str.value = new StringValue( str.value->data );
60 }
61 str.value->shareable = false;
62 return &str.value->data[pos];
63 }
64 //const version of operator ampersand(&) overloading;
65 const char* operator&()const{ return &str.value->data[pos];}
66
67 private:
68 String& str;
69 int pos;
70 };
71
72 String(const char* cszStr = "");
73 String(const String& rhs);
74 String& operator=(const String& rhs);
75 ~String();
76 const char* c_str()const{return value->data;}
77
78public:
79 CharProxy operator[](size_t idx);
80 const CharProxy operator[](size_t idx)const;
81
82public:
83 struct StringValue
84 {
85 size_t refCount;
86 size_t len;
87 bool shareable;
88 char* data;
89
90 StringValue(const char* cszStr);
91 ~StringValue();
92 };
93
94private:
95 StringValue* value;
96};
97#endif
98
文件String.cpp
1#include "String.h"
2#include <string.h>
3#include <assert.h>
4
5String::String(const char* cszStr)
6{
7 value = new StringValue(cszStr);
8}
9
10String::String(const String& rhs)
11{
12 if( rhs.value->shareable )
13 {
14 value = rhs.value;
15 value->refCount++;
16 }
17 else
18 {
19 value = new StringValue(rhs.value->data);
20 }
21}
22
23String& String::operator=(const String& rhs)
24{
25 if( rhs.value == value )return *this;
26
27 if( rhs.value->shareable )
28 {
29 --value->refCount;
30 if( value->refCount == 0 )delete value;
31
32 value = rhs.value;
33 ++value->refCount;
34 }
35 else
36 {
37 value = new StringValue(rhs.value->data);
38 }
39 return *this;
40}
41
42String::~String()
43{
44 if( --value->refCount == 0 )delete value;
45}
46
47String::CharProxy String::operator[](size_t idx)
48{
49 assert( idx < value->len && idx >= 0);
50 return String::CharProxy(*this, idx );
51}
52const String::CharProxy String::operator[](size_t idx)const
53{
54 assert( idx < value->len && idx >= 0);
55 return CharProxy(const_cast<String&>(*this), idx );
56}
57
58String::StringValue::StringValue(const char* cszStr)
59 :refCount(1),shareable(true)
60{
61 len = strlen(cszStr);
62 data = new char[len + 1];
63 if( len == 0 )data[0] = '\0';
64 else strcpy(data, cszStr);
65}
66
67String::StringValue::~StringValue()
68{
69 delete[] data;
70 data = 0;
71}
72
测试程序
1#include <iostream>
2#include "String.h"
3
4using namespace std;
5
6std::ostream& operator<< (std::ostream& os, String& str)
7{
8 os << str.c_str();
9 return os;
10}
11int main()
12{
13 String str1 = "hello";
14 String str2(str1);
15
16 cout << "------initial status------" << endl;
17
18 cout << "\tstr1 = " << str1 << endl;
19 cout << "\tstr2 = " << str2 << endl;
20 printf( "\tstr1 address:%p\n", str1.c_str());
21 printf( "\tstr2 address:%p\n", str2.c_str());
22 cout << endl;
23
24
25 cout << "------after reading str1[0]------" << endl;
26 str1[0];
27 cout << "\tstr1 = " << str1 << endl;
28 cout << "\tstr2 = " << str2 << endl;
29 printf( "\tstr1 address:%p\n", str1.c_str());
30 printf( "\tstr2 address:%p\n", str2.c_str());
31 cout << endl;
32
33 cout << "------after writing str1[0]------" << endl;
34 str1[0] = 'X';
35 cout << "\tstr1 = " << str1 << endl;
36 cout << "\tstr2 = " << str2 << endl;
37 printf( "\tstr1 address:%p\n", str1.c_str());
38 printf( "\tstr2 address:%p\n", str2.c_str());
39 cout << endl;
40
41 cout << "str1 = " << str1 << endl;
42 char& c = str1[1];
43 c = 'Y';
44 cout << "str1 = " << str1 << endl;
45
46 const char& d = str1[1];
47 cout << "the 2nd character is:" << d << endl;
48
49 char* p = &str1[1];
50 *p = 'X';
51 cout << "str1 = " << str1 << endl;
52
53 const char* q = &str1[1];
54 cout << "the 2nd character is:" << *q << endl;
55
56 system("PAUSE");
57 return EXIT_SUCCESS;
58}
59