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

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

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

类声明

  1. 该类中包含了三个构造函数:有参数的构造函数,拷贝构造函数已经移动构造函数
  2. 重载了[],=(一个普通赋值运算符,一个移动赋值运算符),+,==四个运算符
  3. 一个用于求字符长度的方法;一个用于获取C语言类型字符串的方法
  4. 以友元的方式重载了输入流>>和输出流<<操作符

头文件(strings.h)

//
// 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)

//
// 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;
}

调用示例

#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;
}

运行结果:

默认构造函数(Hello)
Hello
5
----------
默认构造函数(Word)
Word
----------
默认构造函数()
HelloWord
9
析构函数(HelloWord)
析构函数(Word)
析构函数(Hello)

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