C++
October 6, 2018

C++实现一个简单的String类

C++实现一个简单的String类

使用基本的C++知识实现一个简单的String类,这个类中包含了C++常用的知识点。感觉是很有意思的一个小代码片段。

跟大家分享一下我的实现,欢迎大家批评指正。

类声明

  1. 该类中包含了三个构造函数:有参数的构造函数,拷贝构造函数已经移动构造函数

  2. 重载了[],=(一个普通赋值运算符,一个移动赋值运算符),+,==四个运算符

  3. 一个用于求字符长度的方法;一个用于获取C语言类型字符串的方法

  4. 以友元的方式重载了输入流>>和输出流<<操作符

头文件(strings.h)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//
// Created by Zhenyu Tan on 2018/10/3.
//
#include <iostream>

class String {
private:
char* _buffer;
size_t _length;
void init(const char* str);

public:
String(const char* str= nullptr); // 默认构造函数
String(const String& other); // 拷贝构造函数
String(String&& other) noexcept; // 移动构造函数
~String(); // 析构函数

size_t length();
const char* data();

char& operator[](size_t index);
String& operator=(const String& other);
String& operator=(String&& other) noexcept;
String operator+(const String& other);
bool operator==(const String& other);

friend std::ostream& operator<<(std::ostream& output, const String& str);
friend std::istream& operator>>(std::istream& input, String& str);
};

类实现

源文件(strings.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//
// Created by Zhenyu Tan on 2018/10/5.
//

#include "strings.h"
#include <cstring>
#include <exception>
#include <iostream>

using std::cout;
using std::ostream;
using std::istream;

size_t String::length() {
if (0 == _length) {
_length = std::strlen(_buffer);
}
return _length;
}

const char* String::data() {
return _buffer;
}


void String::init(const char* str) {
if (nullptr == str) {
_length = 0;
_buffer = nullptr;
} else {
_length = std::strlen(str);
_buffer = new char[_length + 1];
std::strcpy(_buffer, str);
}
}


String::String(const char* str) {
init(str);
cout << "默认构造函数(" << *this << ")\n";
}


String::String(const String& other) {
// 在类的成员函数中可以访问同类型实例的私有变量
init(other._buffer);
cout << "拷贝构造函数(" << *this << ")\n";
}

String::String(String&& other) noexcept {
// 把other对象掏空用来填充this
_buffer = nullptr;
_buffer = other._buffer;
_length = other._length;
other._buffer = nullptr;
other._length = 0;
cout << "移动构造函数(" << *this << ")\n";
}


String::~String() {
delete[] _buffer;
cout << "析构函数(" << *this << ")\n";
}

/*
* 拷贝构造函数使用传入对象的值生成一个新的对象的实例
* 赋值运算符是将对象的值复制给一个已经存在的实例
*/
String& String::operator=(const String& other) {
if (this != &other) {
delete[] _buffer;
init(other._buffer);
}
cout << "拷贝赋值操作(" << *this << ")\n";
return *this;
}

/*
* 移动赋值操作即把参数传进来的对象的所有权转移到this指向的对象
* 掏空other对象的所有
*/
String& String::operator=(String&& other) noexcept {
if (this != &other) {
_buffer = nullptr;
_buffer = other._buffer;
_length = other._length;
other._buffer = nullptr;
other._length = 0;
}
cout << "移动赋值操作(" << *this << ")\n";
return *this;
}


char& String::operator[](size_t index) {
if (index >= _length) {
throw std::out_of_range("Index out of range");
} else {
return _buffer[index];
}
}


bool String::operator==(const String& other) {
if (_length != other._length) {
return false;
} else {
return 0 == std::strcmp(_buffer, other._buffer);
}
}

/*
* 关于是返回对象本身还是返回对象引用
* 如果函数返回在函数中创建的临时对象,则不要使用引用
* 如果函数返回的是通过引用或指针传递给它的对象,则应当按引用返回对象
* 如果先创建一个对象,然后返回改对象的副本,则可以使用返回对象
*/
String String::operator+(const String& other) {
String _str;
if (nullptr == _buffer) {
_str = other;
} else if (nullptr == other._buffer) {
_str = *this;
} else {
_str._buffer = new char[_length + other._length + 1];
std::strcpy(_str._buffer, _buffer);
std::strcat(_str._buffer, other._buffer);
_str._length = std::strlen(_str._buffer);
}
return _str;
}


ostream& operator<<(ostream &output, const String& str) {
if (nullptr == str._buffer) {
output << "";
} else {
output << str._buffer;
}
return output;
}

istream& operator>>(istream &input, String& str) {
input >> str._buffer;
return input;
}

调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "strings.h"
#include <iostream>

using std::cout;

int main() {
String str1("Hello");
cout << str1.data() << '\n';
cout << str1.length() << '\n';
cout << "----------\n";
String str2 = "Word";
cout << str2 << '\n';
cout << "----------\n";
String str3 = str1 + str2;
cout << str3.data() << '\n';
cout << str3.length() << '\n';
return 0;
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
默认构造函数(Hello)
Hello
5
----------
默认构造函数(Word)
Word
----------
默认构造函数()
HelloWord
9
析构函数(HelloWord)
析构函数(Word)
析构函数(Hello)

主程序中的第7行和第11行各自调用一次默认的有参构造函数,第14行是重载的加法运算符中调用了一次无参的构造函数(由于C++编译器的优化,函数返回值没有调用拷贝构造函数)