引言
在学完 C++ 的类、构造函数、析构函数、拷贝控制、运算符重载、模板等核心知识后,动手设计一个完整的类是最好的巩固方式。
今天,我将通过两个实践项目来检验这些知识的掌握程度:
自定义 String 类:模拟标准库
std::string的核心功能顺序栈 Stack 类模板:实现一个通用的栈容器,并完成括号匹配检测
这两个项目涵盖了深拷贝、运算符重载、模板编程、动态内存管理等重要知识点。
第一部分:自定义 String 类
一、设计目标
实现一个类似std::string的字符串类String,支持以下功能:
构造与析构
深拷贝(拷贝构造)
下标访问
[]字符串追加
append和+=字符串查找
find/rfind字符串插入
insert输出流运算符
<<
二、类设计
#include <iostream> #include <cstring> using namespace std; #define BUF_SIZE 8192 class String final { private: char* buffer; // 字符缓冲区 int len; // 字符串长度 public: // 1. 默认构造函数 String() { buffer = new char[BUF_SIZE]{0}; len = 0; } // 2. 带参构造函数(C风格字符串) String(const char* s) { buffer = new char[BUF_SIZE]{0}; memcpy(buffer, s, strlen(s)); len = strlen(s); } // 3. 拷贝构造函数(深拷贝) String(const String& o) { buffer = new char[BUF_SIZE]{0}; memcpy(buffer, o.buffer, o.len); len = o.len; } // 4. 析构函数 ~String() { delete[] buffer; } // 5. 获取长度 int length() const { return len; } // 6. 下标访问运算符(可修改) char& operator[](int index) { static char nochar = '\0'; if (index < 0 || index >= len) return nochar; return buffer[index]; } // 7. 追加字符串 String& append(const char* s) { int s_len = strlen(s); if (len + s_len >= BUF_SIZE) { // 扩容逻辑(可优化) return *this; } memcpy(buffer + len, s, s_len); len += s_len; return *this; } String& operator+=(const char* s) { return append(s); } // 8. 插入字符串 String insert(int pos, const char* ns) const { String result; int ns_len = strlen(ns); // 复制 pos 之前的内容 memcpy(result.buffer, buffer, pos); // 插入新字符串 memcpy(result.buffer + pos, ns, ns_len); // 复制剩余内容 memcpy(result.buffer + pos + ns_len, buffer + pos, len - pos); result.len = len + ns_len; return result; } // 9. 查找子串(从左到右) int find(const char* s) const { int s_len = strlen(s); if (s_len == 0 || s_len > len) return -1; for (int i = 0; i <= len - s_len; i++) { if (buffer[i] == s[0]) { bool found = true; for (int j = 1; j < s_len; j++) { if (buffer[i + j] != s[j]) { found = false; break; } } if (found) return i; } } return -1; } // 10. 查找子串(从右到左) int rfind(const char* s) const { int s_len = strlen(s); if (s_len == 0 || s_len > len) return -1; for (int i = len - s_len; i >= 0; i--) { if (buffer[i] == s[0]) { bool found = true; for (int j = 1; j < s_len; j++) { if (buffer[i + j] != s[j]) { found = false; break; } } if (found) return i; } } return -1; } // 11. 输出运算符重载(成员函数版本) ostream& operator<<(ostream& cout) const { cout << buffer; return cout; } }; // 12. 全局输出运算符重载 ostream& operator<<(ostream& cout, const String& s) { return s.operator<<(cout); }三、测试代码
int main() { // 1. 基本构造与输出 String s = "hello"; cout << s << endl; // hello cout << "长度: " << s.length() << endl; // 5 // 2. 下标修改 s[1] = 'i'; cout << "修改后: " << s << endl; // hillo // 3. 追加 s.append(", diyi").append(" and "); s += "lucy!"; cout << s << endl; // hillo, diyi and lucy! // 4. 插入 String s2 = s.insert(5, " everybody"); cout << s2 << endl; // hillo everybody, diyi and lucy! // 5. 查找 cout << "\"diyi\"位置: " << s2.find("diyi") << endl; // 17 s2[s2.find("diyi")] = 'j'; cout << "替换后: " << s2 << endl; // hillo everybody, jiyi and lucy! // 6. 反向查找 String s3 = "hi,diyi! what are you doing? diyi say sleep!"; cout << "\n原字符串: " << s3 << endl; cout << "第一次出现 diyi: " << s3.find("diyi") << endl; cout << "最后一次出现 diyi: " << s3.rfind("diyi") << endl; s3[s3.rfind("diyi")] = 'k'; cout << "替换后: " << s3 << endl; return 0; }第二部分:顺序栈类模板
一、设计目标
实现一个通用的顺序栈(基于数组),支持任意数据类型,并完成括号匹配检测应用。
栈的特点:后进先出(LIFO,Last In First Out)
二、类模板设计
#define STACK_SIZE 128 template<class T> class Stack { private: T* data; // 动态数组 int last; // 栈顶索引(也是元素个数) int maxSize; // 最大容量 public: // 构造函数 Stack(int maxSize = -1) { this->maxSize = (maxSize == -1) ? STACK_SIZE : maxSize; data = new T[this->maxSize]{ T() }; last = 0; } // 禁止拷贝(栈通常不需要拷贝) Stack(const Stack& o) = delete; void operator=(const Stack& o) = delete; // 析构函数 ~Stack() { delete[] data; } // 入栈 void push(T item) { if (last < maxSize) { data[last++] = item; } } // 出栈 void pop() { if (last > 0) { data[last - 1] = T(); // 重置为默认值 last--; } } // 查看栈顶元素 T peek() const { if (last == 0) return T(); return data[last - 1]; } // 获取元素个数 int size() const { return last; } // 判断是否为空 bool isEmpty() const { return last == 0; } };三、测试代码
1. 基本类型测试
int main() { Stack<int> s1; s1.push(10); s1.push(20); s1.push(100); cout << "栈大小: " << s1.size() << endl; // 3 cout << "栈顶: " << s1.peek() << endl; // 100 cout << "弹出顺序: "; while (s1.size() > 0) { cout << s1.peek() << " "; s1.pop(); } cout << endl; // 100 20 10 return 0; }2. 自定义类型测试
class Person { private: string name; int pid; public: Person() : name(""), pid(0) {} Person(string name, int pid) : name(name), pid(pid) {} void show() const { cout << name << ", " << pid << endl; } }; int main() { Stack<Person> s2; s2.push(Person("dier", 1010)); s2.push(Person("Jack", 2010)); s2.push(Person("Lucy", 1030)); s2.push(Person("Mack", 5010)); while (s2.size() > 0) { s2.peek().show(); s2.pop(); } // 输出顺序(后进先出): // Mack, 5010 // Lucy, 1030 // Jack, 2010 // dier, 1010 return 0; }第三部分:经典应用——括号匹配检测
一、问题描述
给定一个包含括号()、[]、{}的字符串,判断括号是否匹配。
合法示例:()、([])、{([[]])}
非法示例:(]、[)、(((、)))
二、算法思路
三、代码实现
int main() { string s; cout << "请输入测试括号的字符串: "; cin >> s; string lefts = "([{"; string rights = ")]}"; Stack<char> stack(128); bool isValid = true; for (char ch : s) { // 1. 左括号:压栈 if (lefts.find(ch) != string::npos) { stack.push(ch); } // 2. 右括号:匹配检查 else if (rights.find(ch) != string::npos) { if (stack.isEmpty()) { isValid = false; break; } char top = stack.peek(); if ((top == '(' && ch == ')') || (top == '[' && ch == ']') || (top == '{' && ch == '}')) { stack.pop(); } else { isValid = false; break; } } } if (isValid && stack.isEmpty()) { cout << "括号合法!" << endl; } else { cout << "括号不合法!" << endl; } return 0; }# 合法示例 请输入测试括号的字符串: ({[]}) 括号合法! # 非法示例 请输入测试括号的字符串: (] 括号不合法! # 左括号多余 请输入测试括号的字符串: ((() 括号不合法! # 右括号多余 请输入测试括号的字符串: ())) 括号不合法!总结
一、自定义 String 类核心知识点
| 知识点 | 应用 |
|---|---|
| 构造函数 | 默认构造、带参构造、拷贝构造(深拷贝) |
| 析构函数 | delete[]释放动态内存 |
| 运算符重载 | []、+=、<< |
| 访问控制 | private成员、public接口 |
| const 成员函数 | length()、find()、rfind() |
二、Stack 类模板核心知识点
| 知识点 | 应用 |
|---|---|
| 类模板 | template<class T>支持任意类型 |
| 动态内存 | new[]/delete[] |
| 拷贝控制 | 禁用拷贝(= delete) |
| LIFO 特性 | push/pop/peek |
三、两个项目的关联
| 项目 | 核心难点 | 旁白 |
|---|---|---|
| String 类 | 深拷贝、运算符重载 | 模拟标准库行为 |
| Stack 类模板 | 模板编程、泛型 | 可存储任意类型,包括 String |
这两个实践项目覆盖了 C++ 类的核心知识点:
String 类:重点练习了深拷贝(拷贝构造函数)、运算符重载(
[]、+=、<<)、动态内存管理。Stack 类模板:重点练习了模板编程、泛型设计、后进先出的数据结构,并完成了括号匹配的经典应用。