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

{
7
public:
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
78
public:
79
CharProxy operator[](size_t idx);
80
const CharProxy operator[](size_t idx)const;
81
82
public:
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
94
private:
95
StringValue* value;
96
};
97
#endif
98
文件String.cpp
1
#include "String.h"
2
#include <string.h>
3
#include <assert.h>
4
5
String::String(const char* cszStr)
6

{
7
value = new StringValue(cszStr);
8
}
9
10
String::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
23
String& 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
42
String::~String()
43

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

{
49
assert( idx < value->len && idx >= 0);
50
return String::CharProxy(*this, idx );
51
}
52
const 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
58
String::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
67
String::StringValue::~StringValue()
68

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

{
8
os << str.c_str();
9
return os;
10
}
11
int 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