My_string.h
#ifndef MY_STRING_H
#define MY_STRING_H
#include <iostream>
class My_string {
private:
char *ptr; // 指向字符数组的指针
int size; // 字符串的最大容量
int len; // 字符串当前长度
void resize(int new_size);
public:
// 无参构造
My_string();
// 有参构造
My_string(const char* src);
// 拷贝构造
My_string(const My_string& other);
// 拷贝赋值
My_string& operator=(const My_string& other);
// 析构函数
~My_string();
// 判空
bool empty() const;
// 尾插
void push_back(char value);
// 尾删
void pop_back();
// at函数实现
char& at(int index);
// 清空函数
void clear();
// 返回C风格字符串
char* data();
// 返回实际长度
int get_length() const;
// 返回当前最大容量
int get_size() const;
// 打印字符串
void print() const;
};
#endif // MY_STRING_H
My_string.cpp
#include "My_string.h"
#include <cstring> // 用于调用标准库的字符串函数
#include <stdexcept> // 用于抛出异常
using namespace std;
// 无参构造
My_string::My_string() : size(15), len(0) {
ptr = new char[size];
ptr[0] = '\0'; // 表示串为空串
}
// 有参构造
My_string::My_string(const char* src) : size(strlen(src) + 1), len(strlen(src)) {
ptr = new char[size];
strcpy(ptr, src);
}
// 拷贝构造
My_string::My_string(const My_string& other) : size(other.size), len(other.len) {
ptr = new char[size];
strcpy(ptr, other.ptr);
}
// 拷贝赋值
My_string& My_string::operator=(const My_string& other) {
if (this != &other) {
delete[] ptr;
size = other.size;
len = other.len;
ptr = new char[size];
strcpy(ptr, other.ptr);
}
return *this;
}
// 析构函数
My_string::~My_string() {
delete[] ptr;
}
// 判空
bool My_string::empty() const {
return len == 0;
}
// 尾插
void My_string::push_back(char value) {
if (len >= size) {
resize(size * 2);
}
ptr[len++] = value;
ptr[len] = '\0';
}
// 尾删
void My_string::pop_back() {
if (len > 0) {
--len;
ptr[len] = '\0';
}
}
// at函数实现
char& My_string::at(int index) {
if (index < 0 || index >= len) {
throw out_of_range("Index out of range");
}
return ptr[index];
}
// 清空函数
void My_string::clear() {
delete[] ptr;
ptr = new char[size = 15];
ptr[0] = '\0';
len = 0;
}
// 返回C风格字符串
char* My_string::data() {
return ptr;
}
// 返回实际长度
int My_string::get_length() const {
return len;
}
// 返回当前最大容量
int My_string::get_size() const {
return size;
}
// 打印字符串
void My_string::print() const {
cout << ptr << endl;
}
main.cpp
#include "My_string.h"
int main() {
My_string s1("Hello");
My_string s2 = s1; // 拷贝构造
s1.push_back('!');
s1.print();
s2.print();
return 0;
}
思维导图
特殊成员函数
├── 构造函数
│ ├── 功能
│ │ └── 初始化对象
│ ├── 定义格式
│ │ ├── 函数名与类同名
│ │ ├── 没有返回值
│ │ ├── 权限:public
│ │ └── 参数可有可无
│ ├── 调用时机
│ │ ├── 栈区实例化
│ │ └── 堆区使用 new
│ ├── 支持重载
│ │ └── 可以有多个构造函数
│ ├── 默认构造函数
│ │ ├── 如果没有定义构造函数,系统提供默认构造
│ │ └── 定义了构造函数后,需要手动定义无参构造
│ ├── 初始化列表
│ │ ├── 格式:类名(形参列表):成员属性1(形参1), 成员属性2(形参2) {函数体}
│ │ ├── 必须使用初始化列表的情况
│ │ │ ├── const成员属性
│ │ │ ├── 引用成员
│ │ │ └── 其他类的成员子对象
│ └── 构造函数重载
│ └── 可以有多个构造函数,参数不同
├── 析构函数
│ ├── 功能
│ │ └── 回收对象空间
│ ├── 定义格式
│ │ ├── 函数名:~类名
│ │ ├── 没有参数
│ │ └── 没有返回值
│ ├── 一个类中只有一个
│ │ └── 不能重载
│ ├── 默认析构函数
│ │ ├── 系统提供默认析构
│ │ └── 定义析构函数后,需要手动定义
│ ├── 调用时机
│ │ ├── 栈区:对象脱离作用域
│ │ └── 堆区:使用 delete
│ └── 构造函数和析构函数调用顺序
│ ├── 栈区:先构造的后析构,后构造的先析构
│ └── 堆区:new时构造,delete时析构
├── 拷贝构造函数
│ ├── 功能
│ │ └── 使用一个对象初始化另一个
│ ├── 定义格式
│ │ ├── 函数名与类同名
│ │ ├── 返回值:无
│ │ ├── 参数:当前类的其他类对象的引用
│ │ └── 权限:public
│ ├── 调用时机
│ │ ├── 对象初始化
│ │ ├── 函数实参传递
│ │ └── 函数返回值
│ ├── 默认拷贝构造函数
│ │ ├── 系统提供默认拷贝构造
│ │ └── 定义拷贝构造函数后,需要手动定义
│ ├── 深浅拷贝问题
│ │ ├── 浅拷贝:简单赋值
│ │ └── 深拷贝:重新分配内存
├── 拷贝赋值函数
│ ├── 功能
│ │ └── 赋值操作
│ ├── 定义格式
│ │ ├── 函数名:operator=
│ │ ├── 返回值:自身的引用
│ │ ├── 参数:同类的其他对象的引用
│ │ └── 权限:public
│ ├── 默认拷贝赋值函数
│ │ ├── 系统提供默认拷贝赋值
│ │ └── 定义拷贝赋值函数后,需要手动定义
│ └── 深浅拷贝问题
│ ├── 浅拷贝:简单赋值
│ └── 深拷贝:重新分配内存
├── 移动构造函数
│ ├── 功能
│ │ └── 移动对象初始化
│ ├── 定义格式
│ │ ├── 函数名与类同名
│ │ ├── 返回值:无
│ │ ├── 参数:当前类的其他类对象的右值引用
│ │ └── 权限:public
│ └── 调用时机
│ └── 移动语义,如使用 std::move
├── 移动赋值函数
│ ├── 功能
│ │ └── 移动对象赋值
│ ├── 定义格式
│ │ ├── 函数名:operator=
│ │ ├── 返回值:自身的引用
│ │ ├── 参数:同类的其他类对象的右值引用
│ │ └── 权限:public
│ └── 调用时机
│ └── 移动语义,如使用 std::move
└── 取地址运算符重载
├── 功能
│ └── 获取对象地址
└── 定义格式
├── 函数名:operator&
├── 返回值:对象地址
└── 权限:public