1 #include<iostream>
2 #include<string>
3 #include<vector>
4 #include<algorithm>
5 #include<cstdio>
6 #include<complex>
7 #include<new>
8 #include<memory>
9 #include<exception>
10 using namespace std;
11 // interfaces should supported
12 //用char*管理内存
13 class String
14 {
15 public:
16 String();
17 String(const char*s);
18 String(size_t n, const char c);//用字符c填充String
19 String(const String&s);
20 String& operator=(const String&rhs);
21 String& operator=(const char*c);
22 char& operator[](size_t index);//要提供[]的两个版本
23 const char& operator[](size_t index)const;
24 String & operator*();//解引用重载是多余的,语言本身支持对所有类型的指针解引用,包括了自定义类型
25 String& operator+(const String&rhs);
26 String& operator+=(const String&rhs);
27 bool operator==(const String&rhs);
28 friend bool operator<(const String&lhs, const String&rhs);
29 friend ostream& operator<<(ostream& os, const String&rhs);
30 friend istream& operator>>(istream& in, String&rhs);
31 size_t size(); //如果是size_t length()会导致。。。。。
32 bool empty();
33 const char* c_str();
34 ~String();
35 private:
36 char * data;
37 size_t length;
38
39 };
40 String::String() //类外面定义menber function ,域作用符
41 {
42 this->data = new char[1](); //空字符串 ,strlen对data运算得到的长度为0
43 data[0] = '\0';
44 (*this).length = 0;
45 }
46 String::String(const char*s) //允许implicit类型转换
47 {
48 // 不能用data=s;这导致创建的String对象与s共享了字符,而不是副本
49 length = strlen(s);
50 data = new char[length + 1]();//value initialization,申请了字符指针指向的内存区域
51 strcpy(data, s);
52 *(data + length) = '\0';
53 }
54 String::String(size_t n, const char c)
55 {
56 length = n;
57 data = new char[length + 1]();
58 for (size_t i = 0; i < length;i++)
59 {
60 *(data + i) = c;
61 }
62 *(data + length) = '\0';
63 }
64 String::String(const String&s)
65 {
66 length = s.length;
67 data = new char[length + 1](); //untill deconstructor to destory newed memory
68 for (size_t i = 0; i < length;i++)
69 {
70 data[i] = s.data[i];
71 }
72 data[length] = '\0';
73 }
74 String& String::operator=(const String&rhs)
75 {
76 if (this->data == rhs.data) return *this;// 支持*this==rhs的关系比较操作吗?
77
78 //assign 不是初始化,不需要申请内存空间,拷贝构造需要 ,但是原String与rhs大小可能不一样
79 delete[]data; //会导致重复删除data所指内存吗??
80
81 length = rhs.length;
82 data = new char[length + 1]();
83 //如果发生异常
84
85 if (data == NULL) throw "allocate memory failed in copy ctr";
86 for (size_t i = 0; i < length; i++)
87 {
88 data[i] = rhs.data[i];
89 }
90 data[length] = '\0';
91 }
92 char& String::operator[](size_t index)
93 {
94 if (index >= length||index<0) throw "out of range";
95 return data[index];//如果data指向的字符串为"dhaj"这种不可修改的,会导致返回的引用不能有s[i]='c'的修改操作
96 }
97 String& String:: operator*()
98 {
99 if (this == NULL) throw "dereferrence null pointer ";
100 return *this;
101 }
102 String& String::operator+(const String&rhs)//a+b形式,也不改变a
103 {
104 String s;//不可伸缩,不能用来存a+b的结果
105 int len = strlen(this->data) + strlen(rhs.data);
106 char *p = new char[len + 1]();
107 for (size_t i = 0; i < strlen(this->data); i++)
108 {
109 p[i] = this->data[i];
110 }
111 for (int j = strlen(this->data),i=0; j < len; j++,i++)
112 {
113 p[j] = rhs.data[i];
114 }
115 p[len] = '\0';
116 String *t = new String(p); //new了一个p,一个t,可以释放掉p,因为t是p的副本
117 delete[]p;
118 return *t;//返回了堆上的引用,再c=a+b这种使用后,c是会析构的,但中间这个看不见的对象不会析构
119 }
120 String& String::operator+=(const String&rhs)
121 {
122 *this = *this + rhs;
123 //释放掉原来的a,申请新空间
124 return *this;
125 }
126 bool String::operator==(const String&rhs)//比较是否相等,而不是相同
127 {
128 if (this->length != rhs.length) return false;
129 int i = 0;
130 for (; (*this).data[i] == rhs.data[i]; i++);
131 if (i != (rhs.length + 1)) return false;
132 else return true;
133 }
134 bool operator<(const String&lhs, const String&rhs)
135 {
136 return true;
137 }
138 ostream& operator<<(ostream& os, const String&rhs) //申明为友元函数。调用方式为cout<<s,申明为men fun,调用形式为s<<cout
139 {
140 os << rhs.data;//输出null pointer会未定义行为
141 return os;
142 }
143 istream& operator>>(istream& is, String&rhs)
144 {//输入一个字符串到字符指针,字符指针需要预先分配一定大小的空间,如何根据输入的字符串调整空间大小
145 delete[]rhs.data;
146 rhs.data = new char[50]();
147 is.getline(rhs.data, 50);//最后位置自动置为'\0',所以最多存49个字符,可接收空格
148 rhs.length = strlen(rhs.data);
149 return is;
150 }
151 size_t String::size()
152 {
153 return length;
154 }
155 bool String::empty()
156 {
157 if (length == 0) return true;
158 else return false;
159 }
160 const char* String::c_str()//返回指向对象局部部分的引用,指针,能用来修改原对象吗?
161 {//如果为空串,也要返回data
162 return data;
163
164 }
165 String::~String()
166 { // 析构会发生错误吗?
167 //String创建时会new内存,当程序结束或局部String对象退出作用域时调用析构函数,释放该内存
168 delete[]data; //如果String不是new出来的, 指针p指向它,delete p会导致错误,new出来的可以调用delete,这时会调用~String
169 data = NULL;
170 }
171
172 //int main()
173 //{
174 // String s;
175 // cout << s << endl;
176 // cout << strlen(s.c_str()) << endl;
177 // String s1 = "whah";
178 // cout << s1 << endl;
179 // String s2 = s1;
180 // cout <<"s2 length:"<< s2.size() << endl;
181 // s = s2;
182 // cout << "用s2赋值后的s: " << s << endl;
183 // String s3(10, 'c');
184 // cout << "字符填充初始化s3: " << s3 << " " << "s3 len= " << s3.size() << endl;
185 // s3[0] = 'a';
186 // cout << "下标修改s3后: " << s3 << endl;
187 // String s4 = s2 + s3+"ad"; //支持连续的+
188 // cout << s4 << endl;
189 // String *sp = &s4;
190 // cout << *sp << endl;
191 // cout << strlen((*sp).c_str()) << endl;
192 // String *q = new String(*sp);
193 // cout << *q << endl;
194 // delete q;
195 //
196 // char *sq = const_cast<char*> (s4.c_str());
197 // sq[0] = 'l';
198 // cout << sq << endl;
199 // cout << s4 << endl;
200 // const char *cptr = s2.c_str();
201 // string s5 = "";
202 // string s6 = "\0";
203 // cout << s5 << "**" << s6 << s5.size() << s6.size() << endl;
204 // string str = "jadj";
205 // char *sptr = const_cast<char *> (str.c_str());
206 // sptr[0] = 'd';
207 // cout << sptr << " " << str << endl;
208 // String s7(s2);
209 // s7 += s4;
210 // cout << "s7: " << s7.size() << s7 << endl;
211 // const String s8("daj");
212 // //s8[0]; 对const对象的[]调用,不能用non-const menber版本的operator[],要提供 const char& operator[]() const重载版本
213 // //s8 = "djwajk0";
214 //}
215
216 int main()
217 {
218 string s2;
219 cin >> s2;
220 cout << s2 << endl;
221 String s, s1;
222 cin >> s >> s1;//用Enter间隔字符串,可接含有空格的字符串
223 cout << s <<"\n"<< s1 << endl;
224 cout << s1.size() << endl;
225 }