真正去了解如何写一个string类的时候,发现有好多知识点。
- 复制控制(复制构造函数、赋值操作符、析构函数)
- 运算符重载(+, ==, !=, <, <=, >, >=, +=, []等等)
- 深拷贝(对于字符串拷贝的处理)
- 友元(cin, cout)
- 内联函数(为了提高效率,这些函数都是内联函数)
- const的用法(返回值为常量、常量函数、输入为常量)
- 引用(输入为引用、返回值为引用(如+, []))
- 异常安全(operator=)
这些也还只是基本版的内容,还有
- 隐式共享写时拷贝(智能指针)
- C++11的右值引用、Move语义
- iterator
- gcc中string(basic_string)的写法又是另外一种层面的东西了……
本文给出基本版的代码
#include <iostream>
#include <vector>
#include <string>
#include <iomanip> // setw
#include <cstdio>
using namespace std;
class MyString { // inline
public:
// constructor
MyString(const char* str = NULL);
MyString(const MyString&);
MyString(size_t, char); // ? memset?
// destructor
~MyString();
bool empty();
size_t size() const; // string::size_type?
const char* c_str() const;
void swap(MyString&);
// operator +, ==, !=, <, <=, >, >=, +=
char& operator[](size_t); // unsigned int??
MyString& operator=(const MyString&);
MyString operator+(const MyString&) const;
bool operator==(const MyString&);
// friend istream, ostream
friend istream& operator>>(istream&, MyString&);
friend ostream& operator<<(ostream&, MyString&);
private:
char *m_data;
};
int main() {
MyString mstr, s1, s2;
cin >> mstr;
cout << mstr << endl;
mstr[0] = 'k';
cout << mstr << endl;
s1 = s2 = mstr;
s2[2] = '3';
cout << s1 << " " << (s1 == s2) << " " << s2 << endl;
MyString s3(10, 'm');
cout << s3 << endl;
return 0;
}
inline MyString::MyString(const char* str) {
// error C2572: “MyString::MyString”: 重定义默认参数 : 参数 1 // 去掉 = NULL
if (!str) {
m_data = new char[1];
m_data[0] = '\0';
}
else {
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
}
inline MyString::MyString(const MyString &object) {
m_data = new char[object.size() + 1];
strcpy(m_data, object.c_str());
}
inline MyString::MyString(size_t n, char ch) {
m_data = new char[n + 1];
memset(m_data, ch, n);
m_data[n] = '\0';
}
inline MyString::~MyString() {
delete []m_data;
}
size_t MyString::size() const {
return strlen(m_data);
}
const char* MyString::c_str() const {
return m_data;
}
void MyString::swap(MyString &rhs) {
std::swap(m_data, rhs.m_data);
}
char& MyString::operator[](size_t i) {
// 考虑错误处理
return m_data[i];
}
MyString& MyString::operator=(const MyString& rhs) {
if (this != &rhs) {
MyString temp(rhs);
swap(temp);
}
return *this;
}
bool MyString::operator==(const MyString& rhs) {
return strcmp(m_data, rhs.c_str()) ? false : true;
}
MyString MyString::operator+(const MyString& rhs) const {
MyString newS;
//if (!rhs.m_data) { // 不可能为NULL
// newS = *this;
//}
//else if (!this->m_data) {
// newS = rhs.m_data;
//}
//else {
newS.m_data = new char[size() + rhs.size() + 1];
strcpy(newS.m_data, m_data);
strcat(newS.m_data, rhs.m_data);
//}
return newS;
}
istream& operator>>(istream& in, MyString& rhs) {
// 第一种方法:字符串长度受限
//char temp[255];
//in >> setw(255) >> temp;
rhs = MyString(temp); // ok
//rhs = temp;
strcpy(rhs.m_data, temp); // ??有问题,确实有问题,m_data并没有分配空间,因此也可以先分配空间再拷贝
//return in;
// 第二种方法:字符串长度不受限,但在个别情况下有bug,详见注释
//const int BUFFER_SIZE = 255; // 可以以5来做测试
//char buffer[BUFFER_SIZE];
//char *end = buffer + BUFFER_SIZE - 1;
//rhs = ""; // clear
//do {
// *end = '#';
// //in >> setw(BUFFER_SIZE) >> buffer; // 如果输入恰好是BUFFER_SIZE - 1,则会出问题
// //in.get(buffer, BUFFER_SIZE); // 并不能以空格分隔,直接输入换行也会出问题,暂时还不清楚为什么?难道是因为get了两次?
// in.get(buffer, BUFFER_SIZE, ' '); // 如果以空格分隔,又不能识别换行
// rhs += buffer;
//} while (*end == '\0');
//in.get();
http://www.cplusplus.com/reference/istream/istream/get/
The delimiting character is not extracted from the input sequence if found,
and remains there as the next character to be extracted from the stream (see
getline for an alternative that does discard the delimiting character).
//return in;
// 第三种方法:单字符处理,尝试get(char &c)
const int BUFFER_SIZE = 255; // 可以以5来做测试
char buffer[BUFFER_SIZE];
int i = 0;
char ch;
rhs = "";
// 标准输入流忽略空格和\n // http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
do {
in.get(ch);
} while (ch == ' ' || ch == '\n');
while (true) {
if (ch == ' ' || ch == '\n') {
buffer[i] = '\0';
rhs += buffer;
break;
}
else {
buffer[i++] = ch;
if (i == BUFFER_SIZE - 1) {
buffer[i] = '\0';
rhs += buffer;
i = 0;
}
}
in.get(ch);
}
return in;
}
ostream& operator<<(ostream& out, MyString& rhs) {
out << rhs.m_data;
return out;
}
最后附上一些参考资料。
STL 的string类怎么啦?
意图(Intention)、规格(Specification)、实现(Implementation)
标准C++类string的Copy-On-Write技术(一)
引用计数器(智能指针)
C++面试中string类的一种正确写法
C++ string实现原理
C++ string类的隐式共享写时拷贝的实现及设计要点
C++中String类的实现