C++代码解释:实现一个 mystring 类,用于表示字符串,实现构造函数,默认构造长度为 10 的空间,提供打印字符串,获取空间大小,修改内容的成员函数
·
题目
代码
#include <cstring> // 包含字符串处理函数库,如strlen、strncpy等
#include <iostream> // 包含输入输出流库,用于cout等操作
using namespace std; // 使用标准命名空间,避免重复书写std::
class mystring { // 定义mystring类,用于字符串处理
private: // 私有成员,仅类内部可访问
char* str; // 指向动态分配的字符数组,存储字符串内容
size_t len; // 存储字符串占用的空间大小(包括结束符'\0')
public: // 公有成员,类外部可访问
// 默认构造函数,创建长度为10的空字符串
mystring() : len(10) { // 初始化列表,将len初始化为10
str = new char[len]; // 动态分配长度为len的字符数组
// 初始化为空字符串
str[0] = '\0'; // 将第一个字符设为结束符,代表空字符串
}
// 打印字符串内容(const成员函数,不修改对象状态)
void print() const {
cout << str << endl; // 输出字符串内容并换行
}
// 获取空间大小(const成员函数,不修改对象状态)
size_t getSize() const {
return len; // 返回字符串占用的空间大小
}
// 修改字符串内容,确保不越界
void setContent(const char* newStr) { // 参数为常量字符串指针,避免修改源字符串
// 取新字符串长度和现有空间较小值(减1是预留结束符位置),防止越界
size_t newLen = min(strlen(newStr), len - 1); // strlen获取新字符串实际长度
strncpy(str, newStr, newLen); // 安全复制字符串,最多复制newLen个字符
// 确保以'\0'结尾,避免输出乱码
str[newLen] = '\0'; // 在复制的字符末尾添加结束符
}
// 析构函数,释放动态分配的内存,防止内存泄漏
~mystring() {
delete[] str; // 释放动态分配的字符数组
}
};
// 测试mystring类的功能
int main() {
mystring s; // 创建mystring类的对象s,调用默认构造函数
cout << "空间大小: " << s.getSize() << endl; // 输出对象s的空间大小
s.setContent("Hello"); // 调用setContent方法,设置字符串为"Hello"
cout << "字符串内容: "; // 输出提示信息
s.print(); // 调用print方法,输出字符串内容
s.setContent("World! Long Text"); // 设置较长的字符串(会被截断以适应空间)
cout << "修改后内容: "; // 输出提示信息
s.print(); // 输出修改后的字符串内容
return 0; // 程序正常结束
}
关键点说明:
- 构造函数:
mystring()中动态分配内存,默认创建长度为 10 的字符数组,并初始化为空字符串。 setContent:用strncpy保证不会越界,最后手动加'\0'确保字符串正确结束。- 析构函数:用
delete[]释放动态分配的内存,避免内存泄漏。 const成员函数:print和getSize不会修改对象状态,标记为const更安全。
从代码设计角度来看,是否使用 protected(保护成员),取决于类的 继承需求 和 设计意图 。以下从几个维度解释当前代码没用到 protected 的原因,以及何时适合用 protected :
1. 类的定位:无需继承扩展
当前 mystring 类是一个 独立功能类 ,设计目标是封装字符串的基础操作(构造、打印、修改内容等),没有考虑让其他类继承它 。
protected的核心作用是 给子类开放访问权限 (子类可访问父类的protected成员,外部类 / 函数不行 )。- 如果类不需要被继承扩展,所有成员用
private(隐藏实现细节) +public(开放对外接口) 即可,protected就用不上。
2. 设计原则:隐藏实现细节
代码里 str 和 len 是 private ,这是 封装思想 的体现:
private强制外部代码通过public接口(如print、getSize、setContent)操作类,避免直接篡改内部状态(比如直接修改str指针导致内存混乱 )。- 如果把
str或len设为protected,子类继承后能直接访问 / 修改它们,可能破坏父类的封装逻辑(比如子类不小心改坏str指针,父类功能就会异常 )。
3. 何时需要 protected ?
如果有 继承扩展场景 ,比如:
// 假设要继承 mystring 扩展功能
class myAdvancedString : public mystring {
public:
void doSomething() {
// 子类想直接访问父类的 len(假设 len 是 protected)
// 如果父类 len 是 private,这里会编译报错;是 protected 则可以访问
size_t parentLen = len;
// ... 基于父类状态扩展逻辑
}
};
这种情况下,若希望 子类能访问父类的部分内部成员 (但又不想完全开放给外部 ),就可以把这些成员设为 protected 。
总结
当前 mystring 类因为 不需要被继承 ,所以用 private 隐藏实现、public 开放接口就足够,无需 protected 。如果未来有继承扩展需求,再根据实际场景(需要子类访问哪些内部成员 )决定是否引入 protected 。
更多推荐
所有评论(0)