c++--面向对象封装--实践
#include <iostream>
#include <cstring>
using namespace std;class mystring {
private:char* buf; // 指向存储字符串的堆空间int len; // 记录字符串长度public:// 可隐式调用的单参构造函数,使用列表初始化lenmystring(const char* s = "") : len(strlen(s)) {buf = new char[len + 1];strcpy(buf, s);}// 析构函数~mystring() {delete[] buf;}// 拷贝构造函数mystring(const mystring& other) : len(other.len) {buf = new char[len + 1];strcpy(buf, other.buf);}// 赋值运算符重载mystring& operator=(const mystring& other) {if (this != &other) {delete[] buf;len = other.len;buf = new char[len + 1];strcpy(buf, other.buf);}return *this;}// 复制函数 - 接受mystring对象void copy(const mystring& other) {delete[] buf;len = other.len;buf = new char[len + 1];strcpy(buf, other.buf);}// 复制函数 - 接受C风格字符串void copy(const char* s) {delete[] buf;len = strlen(s);buf = new char[len + 1];strcpy(buf, s);}// 追加函数 - 接受mystring对象void append(const mystring& other) {char* temp = new char[len + other.len + 1];strcpy(temp, buf);strcat(temp, other.buf);delete[] buf;buf = temp;len += other.len;}// 追加函数 - 接受C风格字符串void append(const char* s) {int slen = strlen(s);char* temp = new char[len + slen + 1];strcpy(temp, buf);strcat(temp, s);delete[] buf;buf = temp;len += slen;}// 比较函数 - 接受mystring对象int compare(const mystring& other) const {return strcmp(buf, other.buf);}// 比较函数 - 接受C风格字符串int compare(const char* s) const {return strcmp(buf, s);}// 显示字符串void show() const {cout << buf << endl;}// 返回指定位置的字符char at(int pos) const {if (pos >= 0 && pos < len) {return buf[pos];}return '\0'; // 位置无效时返回空字符}
};int main() {mystring str = "hello"; // 隐式调用单参构造函数mystring ptr = "world"; // 使用列表初始化lenstr.copy(ptr);str.copy("你好");str.append(ptr);str.append("你好");str.compare(ptr);str.compare("你好");str.show(); // 输出结果cout << str.at(0) << endl; // 输出第0个字符return 0;
}
以下是对 mystring 类实现的详细解析,按功能模块和关键设计点逐一说明:
1. 类的私有成员
cpp
运行
private:
char* buf; // 指向存储字符串的堆空间
int len; // 记录字符串长度设计目的:
使用动态内存分配(堆空间),避免固定大小数组的限制(如 char buf[256])。
len 存储字符串实际长度,避免重复调用 strlen() 提高效率。
2. 构造函数
cpp
运行
mystring(const char* s = "") : len(strlen(s)) {
buf = new char[len + 1];
strcpy(buf, s);
}关键点:
单参构造函数:参数为 const char*,支持隐式类型转换(如 mystring str = "hello";)。
列表初始化:len(strlen(s)) 在对象构造前初始化 len,比在函数体中赋值更高效。
内存分配:new char[len + 1] 分配足够空间(含字符串结束符 '\0')。
字符串复制:strcpy 将输入字符串复制到堆空间。
3. 析构函数
cpp
运行
~mystring() {
delete[] buf;
}内存管理:释放 buf 指向的堆空间,防止内存泄漏。
若不定义析构函数,对象销毁时 buf 的内存不会自动释放。
4. 拷贝构造函数
cpp
运行
mystring(const mystring& other) : len(other.len) {
buf = new char[len + 1];
strcpy(buf, other.buf);
}深拷贝:
分配新的内存空间,复制原对象的字符串内容。
避免浅拷贝(直接复制指针)导致多个对象共享同一块内存,析构时重复释放。
5. 赋值运算符重载
cpp
运行
mystring& operator=(const mystring& other) {
if (this != &other) {
delete[] buf;
len = other.len;
buf = new char[len + 1];
strcpy(buf, other.buf);
}
return *this;
}自我赋值检查:if (this != &other) 避免自我赋值时释放内存后再复制。
步骤:
释放当前对象的内存。
分配新内存并复制字符串内容(深拷贝)。
返回引用:支持链式赋值(如 a = b = c)。
6. 复制函数(copy)
cpp
运行
void copy(const mystring& other) { ... }
void copy(const char* s) { ... }重载实现:
接受 mystring 对象:复制其 len 和 buf 内容。
接受 const char*:计算长度并复制字符串。
内存管理:
先释放当前 buf 的内存,再分配新内存,防止内存泄漏。
7. 追加函数(append)
cpp
运行
void append(const mystring& other) { ... }
void append(const char* s) { ... }步骤:
计算新长度 len + other.len(或 len + strlen(s))。
分配临时空间 temp,复制原字符串和追加内容。
释放原 buf,将 temp 赋值给 buf。
动态扩展:避免固定大小数组的限制,但需注意频繁追加可能导致性能开销。
8. 比较函数(compare)
cpp
运行
int compare(const mystring& other) const { ... }
int compare(const char* s) const { ... }使用 strcmp:
返回值:
< 0:当前字符串小于参数。
0:字符串相等。
> 0:当前字符串大于参数。
const 修饰:标记为常量成员函数,不修改对象状态。
9. 显示函数(show)
cpp
运行
void show() const {
cout << buf << endl;
}输出字符串:直接打印 buf,利用 cout 对 char* 的重载。
const 修饰:不修改对象状态。
10. 字符访问函数(at)
cpp
运行
char at(int pos) const {
if (pos >= 0 && pos < len) {
return buf[pos];
}
return '\0'; // 位置无效时返回空字符
}边界检查:确保访问位置合法,避免越界。
安全性:返回 '\0'(而非未定义行为),增强程序健壮性。
11. 主函数测试
cpp
运行
int main() {
mystring str = "hello"; // 隐式构造
mystring ptr = "world";
str.copy(ptr); // 复制 "world"
str.copy("你好"); // 复制 "你好"
str.append(ptr); // 追加 "world"
str.append("你好"); // 追加 "你好"
str.compare(ptr); // 比较
str.compare("你好"); // 比较
str.show(); // 输出:你好world你好
cout << str.at(0) << endl; // 输出:你
}功能验证:依次测试构造、复制、追加、比较、显示和字符访问。
总结
该实现通过动态内存管理和深拷贝机制,解决了固定大小数组的限制和浅拷贝导致的内存问题。每个成员函数都遵循以下原则:内存安全:避免泄漏和野指针。
功能完整:提供字符串操作的核心功能。
异常安全:边界检查和状态维护。
性能优化:减少不必要的内存操作和字符串长度计算。通过这些设计,mystring 类实现了一个简单但功能完整的字符串管理系统。
简化易理解版本代码
#include <iostream>
#include <cstring>
using namespace std;class mystring {
private:char* buf;int len;public:mystring() {}mystring(const char* r);void copy(mystring r); bool compare(mystring r);void append(mystring r);char at(int index);void show();
};mystring::mystring(const char* r): len(strlen(r)), buf((char*)calloc(1, len + 1)) {strncpy(buf, r, len);
}void mystring::copy(mystring r) {if (len < r.len) {len = r.len;free(buf);buf = (char*)calloc(1, len + 1);}strncpy(buf, r.buf, len);
}bool mystring::compare(mystring r) {return strcmp(buf, r.buf) == 0;
}void mystring::append(mystring r) {len = len + r.len;char* temp = buf;buf = (char*)calloc(1, len + 1);strcpy(buf, temp);strcat(buf, r.buf);
}char mystring::at(int index) {return buf[index];
}void mystring::show() {cout << buf << endl;
}int main(int argc, const char** argv) {mystring str = "hello";mystring ptr = "world";str.show();ptr.show();str.copy(ptr);str.show();str.copy("aefserfsrfgresfg");str.show();cout << (str.compare(ptr)) << endl;cout << (str.compare("world")) << endl;str.append(ptr);str.show();str.append("world");str.show();cout << str.at(10) << endl;return 0;
}