1:实现一个字符串类。 简单汇总
最简单的方案,使用一个字符串指针,以及实际字符串长度即可。
参考stl的实现,为了提升string的性能,实际上单纯的字符串指针和实际长度是不够了,如上,有优化方案,除此之外,考虑reserve() 以及重置容量,迭代器的相关实现逻辑 (小字符串的存储优化,结合占用内存大小(4的倍数)分配适当的缓冲区更好)。
类中如果没有成员变量,类的大小为1,如果有成员变量,类的大小即为成员变量的大小。(以前研究过 sizeof(string)的长度 可能是28 或者32)
2:实现注意细节
1:c字符串指针+ 实际字符串的长度进行数据存储
2:内存的申请和释放 用new/delete 或者malloc/free都可以吧, 字符串的赋值借用strcpy 或者memcpy都可以吧。
3:默认构造函数 c字符串传参构造 拷贝构造(深拷贝) 移动构造(浅拷贝 std::move) 赋值复制构造 赋值移动构造(右参std::move)
4:注意整个过程中 const参数的修饰,以及相关函数返回值 返回引用对象和返回对象。
5:重载必要的运算符(+ = == ),输入输出的重载(<< >>),注意重载<<和>>时和friend关键字配合,以及实现细节。
6:c字符串相关函数(strcpy strcmp strlen strcat strchr)
3:源码测试
3.1 类的声明(思考const,noexcept修饰,复制传参,引用传参,以及返回值返回引用 返回对象)
/*************************************
1:不需要考虑太多,直接字符串指针和长度进行实现。
2:考虑该类的大小,如果字符串为null时,如果字符串有长度时。 (字符串拼接 截断等)
3:字符串性能的优化,短字符串直接存栈中,长的进行申请。 其他考虑迭代器等的实现方案。只考虑指针和长度进行实现:1:默认构造函数。2:C字符串初始化,直接初始化,移动构造。 拷贝构造函数,赋值构造函数。3:重载运算符 = == + << >> +=
**************************************/
#include <iostream>
#include <cstring>#include <stdio.h>
class my_string
{
private:char* data;size_t length;public://默认构造函数 c字符串构造 拷贝构造函数 移动构造函数 赋值构造函数 my_string();my_string(const char* str);my_string(const my_string& other);my_string(my_string&& other) noexcept;~my_string();size_t size() const;const char* c_str() const;//= == + <<my_string& operator = (const my_string& other) noexcept; //赋值构造函数 复制my_string& operator = (my_string&& other) noexcept; //移动赋值构造函数bool operator==(const my_string& other) const;my_string operator +(const my_string& other) const;
//注意friend的定义friend std::ostream& operator<<(std::ostream& os, const my_string& str);friend std::istream& operator>>(std::istream& in, my_string& str); //输入需要可修改
};
3.2 类的定义
//函数前面用const 表示的是函数返回值const
//函数后面用用const修饰 可以使常量调用,表示该函数内部不可以修改成员变量
my_string::my_string() :data(nullptr), length(0)
{printf("my_string() \n");data = new char[1];data[0] = '\0';
}//c字符串对string进行初始化 c字符串为NULL 不为NULL
//以及c字符串本身也是一以\0终止
my_string::my_string(const char* str)
{printf(" my_string(const char * str) = %s \n", str);if (str){length = strlen(str); //str为NULL 会导致抛异常 data = new char[length + 1];strcpy(data, str);}else{data = new char[1];data[0] = '\0';length = 0;}
}//字符串之间 拷贝构造函数 使用传递引用的方式提升性能
//在自己类的成员函数中 参数可以直接访问私有成员
my_string::my_string(const my_string& other)
{printf(" my_string(const my_string & str) = %s \n", other.data);length = other.length;data = new char[length + 1];strcpy(data, other.data);
}//移动构造函数 注意&& 浅拷贝
my_string::my_string(my_string&& other) noexcept
{printf(" my_string(my_string && str) = %s \n", other.data);//不用申请内存 直接进行赋值即可data = other.data;length = other.length;other.data = nullptr;other.length = 0;
}my_string::~my_string()
{printf("~my_string() = %s \n", data);if(data)delete[]data;
}size_t my_string::size() const
{return length;
}const char* my_string::c_str() const
{return data;
}//= == + <<
//深拷贝 注意对象可能同一个 返回对象的引用
my_string& my_string::operator = (const my_string& other) noexcept//赋值构造函数 复制
{printf("operator = (const my_string & other) = %s \n", other.data);if (this == &other){return *this;}//赋值 先清理 再赋值delete[]data;length = other.length;data = new char[length + 1];strcpy(data, other.data);return *this;
}//浅拷贝 注意对象可能一个 返回引用
my_string& my_string::operator = (my_string&& other) noexcept //移动赋值构造函数
{printf("operator = (my_string && other) = %s \n", other.data);if (this == &other){return *this;}data = other.data;length = other.length;other.data = nullptr;other.length = 0;return *this; //返回对象的引用
}//判断两个字符串相等
bool my_string::operator==(const my_string& other) const
{printf("operator==(const my_string &other) = %s \n", other.data);return strcmp(data, other.data) == 0;
}my_string my_string::operator +(const my_string& other) const
{printf("operator +(const my_string & other) = %s \n", other.data);my_string NewString;NewString.length = length + other.length;NewString.data = new char[NewString.length + 1];strcpy(NewString.data, data);strcpy(NewString.data, other.data);return NewString; //函数中定义的对象 返回该拷贝
}
注意operator<< 和operator>>和friend的细节。
//输出
std::ostream& operator <<(std::ostream& os, const my_string& str)
{os << str.data;return os;
}
std::istream& operator>>(std::istream& in, my_string& str)
{//或者按行输入获取字符串const size_t BUFFER_SIZE = 1024;char buffer[BUFFER_SIZE] = { 0 };in >> buffer;str.length = strlen(buffer);delete[] str.data; //理论上都是已有对象进行输入 str.data = new char[str.length + 1];strcpy(str.data, buffer);return in;
}
3.3 测试代码
int main()
{//默认构造函数测试my_string str; //默认构造函数my_string str_c("c string"); //c字符串构造my_string str_str(str_c); //拷贝构造吧printf("size = %d dara = %s \n", str_str.size(), str_str.c_str());my_string str_move(std::move(str_str)); //移动语义if (str_str.c_str() == nullptr){printf("size = %d dara = nullptr \n", str_str.size());}printf("size = %d dara = %s \n", str_move.size(), str_move.c_str());std::cout << "\nos =" << str_move << std::endl;
//直接初始化 my_string str_move1 = std::move(str_move);std::cout << "\nstr_move1 =" << str_move1 << std::endl;//std::cout << "\nstr_move =" << str_move << std::endl;//赋值构造my_string str_cp = str_move1;std::cout << "\nstr_move1 =" << str_move1 << std::endl;std::cout << "\nstr_cp =" << str_cp << std::endl;
//赋值初始化 my_string str_cp_by_operator;my_string str_move_by_operator;str_cp_by_operator = str_cp;std::cout << "\nstr_cp_by_operator =" << str_cp_by_operator << std::endl;std::cout << "str_cp =" << str_cp << std::endl;str_move_by_operator = std::move(str_cp);std::cout << "\nstr_move_by_operator =" << str_cp_by_operator << std::endl;if (str_cp.c_str() != nullptr){std::cout << "str_cp =" << str_cp << std::endl;}if (str_cp_by_operator == str_move_by_operator){printf("\n operator == is success! \n");}else{printf("\n operator == is failed! \n");}my_string add = str_cp_by_operator + str_move_by_operator;std::cout << "add =" << add << std::endl;printf("please input str:==>");std::cin >> str;std::cout << "os =" << str << std::endl;return 0;
}