深入剖析C++中 String 类的模拟实现
目录
引言
一、基础框架搭建
成员变量与基本构造函数
析构函数
二、拷贝与赋值操作
深拷贝的拷贝构造函数
赋值运算符重载
三、字符串操作功能实现
获取字符串长度
字符串拼接
字符串比较
字符访问
四、迭代器相关实现(简单模拟)
迭代器类型定义
迭代器获取函数
五、总结
引言
在C++ 编程世界里, string 类是处理字符串的重要工具。标准库中的 string 类功能强大且使用便捷,但深入理解其底层实现原理,对提升C++ 编程能力大有裨益。今天,我们就来全面模拟实现一个功能较为完备的 String 类,涵盖构造、拷贝、赋值、析构以及丰富的字符串操作等功能。
一、基础框架搭建
成员变量与基本构造函数
cpp
class String {
private:
char* _str; // 用于存储字符串
public:
// 构造函数,默认构造空字符串
String(const char* str = "") {
if (str == nullptr) {
// 若传入指针为空,视为错误情况,这里简单断言并处理
assert(false);
_str = new char[1];
*_str = '\0';
return;
}
// 计算字符串长度并分配内存
size_t len = strlen(str);
_str = new char[len + 1];
// 复制字符串内容
strcpy(_str, str);
}
上述构造函数处理了传入正常字符串以及空指针的情况,为对象正确初始化字符串存储空间。
析构函数
cpp
~String() {
// 释放字符串占用的动态内存
if (_str) {
delete[] _str;
_str = nullptr;
}
}
析构函数负责在对象生命周期结束时,释放动态分配的内存,防止内存泄漏。
二、拷贝与赋值操作
深拷贝的拷贝构造函数
cpp
// 拷贝构造函数,采用深拷贝方式
String(const String& s) {
size_t len = strlen(s._str);
_str = new char[len + 1];
strcpy(_str, s._str);
}
深拷贝保证了新创建的对象拥有独立的字符串副本,与原对象互不干扰,避免了浅拷贝可能引发的资源共享和释放问题。
赋值运算符重载
cpp
// 赋值运算符重载
String& operator=(const String& s) {
if (this!= &s) { // 避免自我赋值
char* tmp = new char[strlen(s._str) + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
}
return *this;
}
该实现先为新值分配内存,复制内容后再释放原字符串内存,保证了赋值操作的正确性和安全性。同时处理了自我赋值的情况,防止错误发生。
三、字符串操作功能实现
获取字符串长度
cpp
size_t size() const {
return strlen(_str);
}
通过调用标准库的 strlen 函数,返回当前字符串的长度。
字符串拼接
cpp
String operator+(const String& s) const {
size_t len1 = strlen(_str);
size_t len2 = strlen(s._str);
char* result = new char[len1 + len2 + 1];
strcpy(result, _str);
strcat(result, s._str);
String newStr(result);
delete[] result;
return newStr;
}
该函数实现了两个 String 对象的拼接操作。先计算拼接后字符串的总长度,分配足够内存,然后依次复制两个字符串内容,最后返回新的 String 对象。
字符串比较
cpp
int compare(const String& s) const {
return strcmp(_str, s._str);
}
利用标准库的 strcmp 函数实现字符串的字典序比较,返回值小于0表示当前字符串小于传入字符串,等于0表示两者相等,大于0表示当前字符串大于传入字符串。
字符访问
cpp
char& operator[](size_t index) {
assert(index < strlen(_str));
return _str[index];
}
const char& operator[](size_t index) const {
assert(index < strlen(_str));
return _str[index];
}
提供了像数组一样通过下标访问字符的功能,同时区分了常量对象和非常量对象的访问方式,保证了操作的安全性和正确性。
四、迭代器相关实现(简单模拟)
迭代器类型定义
cpp
typedef char* iterator;
typedef const char* const_iterator;
定义了普通迭代器和常量迭代器类型,方便对字符串进行遍历操作。
迭代器获取函数
cpp
iterator begin() {
return _str;
}
iterator end() {
return _str + strlen(_str);
}
const_iterator begin() const {
return _str;
}
const_iterator end() const {
return _str + strlen(_str);
}
这些函数分别返回字符串起始和结束位置的迭代器,支持通过迭代器对字符串进行遍历,如:
cpp
String s("hello");
for (String::iterator it = s.begin(); it!= s.end(); ++it) {
std::cout << *it;
}
五、总结
通过以上一系列的实现,我们构建了一个功能相对丰富的 String 类模拟版本。从基本的对象生命周期管理(构造、析构),到关键的拷贝与赋值操作,再到多样化的字符串操作以及简单的迭代器支持,每一个部分都精心设计,确保正确性和高效性。理解这些底层实现原理,不仅能让我们更好地使用标准库中的 string 类,还能在面对复杂字符串处理需求时,具备更强的代码设计和优化能力。在实际编程中,我们可以根据具体场景进一步扩展和完善这个 String 类,使其发挥更大的作用。