马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、实现 String 类
1.string 类先容
string 类是 c++ 里一个字符串操纵相关的类,简化了一些复杂的字符串操纵。
- int main() {
- // 定义字符数组并初始化
- char str[32] = "hello world";
- char str2[32] = "";
- // 字符串拷贝
- strcpy(str2, str);
- printf("str2 = %s\n", str2);
-
- // 字符串长度
- int len = strlen(str2);
- printf("str2长度为:%d\n", len);
- // 比较字符串大小
- char str3[32] = "hallo world";
- int ret = strcmp(str2, str3);
- if (ret > 0)
- printf("%s 大于 %s\n", str2, str3);
- else if (ret == 0)
- printf("%s 等于 %s\n", str2, str3);
- else
- printf("%s 小于 %s\n", str2, str3);
- return 0;
- }
复制代码
- str2 = hello world
- str2长度为:11
- hello world 大于 hallo world
复制代码
- int main() {
- // 定义字符数组并初始化
- string str = "hello world";
- string str2 = "";
- // 字符串拷贝
- str2 = str;
- cout << "str2 = " << str2 << endl;
- // 字符串长度
- int len = str2.size();
- cout << "str2长度为:" << len << endl;
- // 比较字符串大小
- string str3 = "hallo world";
- if (str2 > str3)
- cout << str2 << " 大于 " << str3 << endl;
- else if (str2 == str3)
- cout << str2 << " 等于 " << str3 << endl;
- else
- cout << str2 << " 小于 " << str3 << endl;
- return 0;
- }
复制代码
- str2 = hello world
- str2长度为:11
- hello world 大于 hallo world
复制代码
- 说明:上面分别是C语言实现的字符串的根本操纵,以及通过c++ string 类实现的字符串的根本操纵,可以看出,string 类用起来会更加方便。
2.实现本身的 MyString 类
这里实现一些 String 类中比较简朴常用的功能。
2.1 MyString 类的成员
先设计好 MyString 类有哪些成员变量和成员函数。
- // 定义一个 MyString 类
- class MyString
- {
- friend istream& operator>>(istream &in, MyString &obj);
- friend ostream& operator<<(ostream &out, MyString obj);
- private:
- // 字符串的长度
- int size;
- // z字符串首元素地址
- char *str;
- public:
- // 构造函数
- MyString();
- MyString(char *str);
- MyString(const MyString &obj);
- // 析构函数
- ~MyString();
- // 获取字符串的长度
- int Size();
- // 重载运算符
- char& operator[](int index);
- MyString& operator=(MyString &obj);
- MyString& operator=(char *str);
- bool operator>(MyString &obj);
- bool operator==(MyString &obj);
- bool operator<(MyString &obj);
- bool operator>(char *str);
- };
复制代码 2.2实现 MyString 的拷贝析构
MyString 类的无参构造、有参构造、拷贝构造、析构函数的代码实现。
- MyString::MyString() {
- size = 0;
- str = NULL;
- }
- MyString::MyString(char *str) {
- size = strlen(str);
- // 多加一个放 \0
- this->str = new char[size + 1];
- // strcpy 会拷贝 \0
- strcpy(this->str, str);
- }
- MyString::MyString(const MyString &obj) {
- size = obj.size;
- this->str = new char[size + 1];
- strcpy(str, obj.str);
- }
- MyString::~MyString() {
- if (str != NULL)
- {
- delete [] str;
- str = NULL;
- }
- }
复制代码 2.3得到字符串的长度
即得到字符串对象中第一个字符到 \0 之间的字符的个数。
- int MyString::Size() {
- return size;
- }
复制代码 2.4输出字符串
如果我们直接 cout 输出字符串对象,因为对象中的成员除了字符串首元素地址,还有字符串的长度,因此不能直接输出,须要重载 << 运算符,又因为运算符的左值不是自界说对象,因此要通过全局函数重载 << 运算符,同时别忘了将函数添加友元。
- // 打印字符串,重载 << 运算符
- ostream& operator<<(ostream &out, MyString obj)
- {
- out << obj.str;
- return out;
- }
复制代码 2.5输入字符串
键盘获取输入,为对象中成员变量赋值,但是须要实现cin >> 字符串对象,须要重载 >> 运算符。其左值也是一个非自界说对象,因此通过全局函数实现,将全局函数设置为友元。
- // 输入字符串,重载 >> 运算符
- istream& operator>>(istream &in, MyString &obj)
- {
- // 如果字符串不为空,先指向空
- if (obj.str != NULL)
- {
- delete [] obj.str;
- obj.str = NULL;
- }
- // 定义一个临时变量存放键盘输入的值
- char temp[1024] = "";
- in >> temp;
- obj.size = strlen(temp);
- obj.str = new char[obj.size + 1];
- strcpy(obj.str, temp);
- return in;
- }
复制代码
- 说明:
- 这里的输入不是追加,因为不知道用户具体会输入多少字符,不确定以前的空间是否足够,因此先判断以前的空间是否为 NULL ,开释之前的空间,申请新空间存放字符串;
- 因为不确定用户输入多少字符串,不知道该申请多大的空间,于是通过一个暂时变量保存字符串,再测字符串长度,根据现实长度申请堆区空间;
- 这里是要对对象的字符串指针变量写入值,要改变其内容,因此利用引用传递。
2.6操纵单个字符
操纵单个字符,就是通过下标索引,读取或修改字符串中的某个字符,须要重载 [] 运算符。左值为自界说对象,通过类的成员函数实现运算符重载。
- char &MyString::operator[](int index) {
- // 先判断是否为空
- if (NULL == str)
- {
- cout << "字符串为空,无法操作" << endl;
- exit(-1);
- }
- // 判断索引是否越界
- if (index >=0 && index <size)
- {
- return str[index];
- }
- else
- {
- cout << index << "越界" << endl;
- exit(-1);
- }
- }
复制代码
2.7对象给对象赋值
一个对象给另外一个对象赋值,须要重载 = 运算符,同时考虑两种情况,一种是 对象1 = 对象2,另一种是对象 = 字符串。
- // 对象赋值给对象
- MyString& MyString::operator=(MyString &obj) {
- // 先判断左值是否为空,非空要先释放
- if (str != NULL)
- {
- delete [] str;
- str = NULL;
- }
- // 将右变对象的值拷贝给左边对象,深拷贝
- size = obj.size;
- str = new char[size + 1];
- strcpy(str, obj.str);
- return *this;
- }
- // 将字符串赋值给对象
- MyString& MyString::operator=(char *str) {
- // 先判断左值是否为空,非空要先释放
- if (this->str != NULL)
- {
- delete [] this->str;
- this->str = NULL;
- }
- // 将右变对象的值拷贝给左边对象,深拷贝
- size = strlen(str);
- this->str = new char[size + 1];
- strcpy(this->str, str);
- return *this;
- }
复制代码
- 说明:
- 上面的第一个函数中,如果返回值为引用,那么参数也必须为引用,且第二个参数的返回值也必须为引用,目的是为了保证链式操纵中类型匹配;
- 假设一种情况 str3 = str2 = str1 = "hello world":会先执行str1 = "hello world",调用上面的第二个函数,然后将赋值后的 str1 的引用返回。此时再执行str2 = str1,将上一次执行的效果作为参数传给第一个函数的 MyString &obj,参数为引用,类型匹配,如果第二个函数返回的是值不是引用,那么这里的链式操纵就完成不了。完成了将 str1 的值赋给 str2 后,会继承返回 str2 的引用,再次调用第一个函数,将上一次执行的效果 str2 的引用传给MyString &obj,如果第一个函数的返回值不是引用,是值的话,这里传参对值取别名会报错,因此返回值和参数的类型必须匹配。
2.8比较字符串对象大小
比较字符串大小,即重载 > < == 运算符。
- // 重载 > 运算符
- bool MyString::operator>(MyString &obj) {
- if ((str == NULL) || (obj.str == NULL))
- {
- cout << "存在空字符串,无法比较" << endl;
- exit(-1);
- }
- if (strcmp(str, obj.str) > 0)
- return true;
- return false;
- }
- // 重载 == 运算符
- bool MyString::operator==(MyString &obj) {
- if ((str == NULL) || (obj.str == NULL))
- {
- cout << "存在空字符串,无法比较" << endl;
- exit(-1);
- }
- if (strcmp(str, obj.str) == 0)
- return true;
- return false;
- }
- // 重载 < 运算符
- bool MyString::operator<(MyString &obj) {
- if ((str == NULL) || (obj.str == NULL))
- {
- cout << "存在空字符串,无法比较" << endl;
- exit(-1);
- }
- if (strcmp(str, obj.str) < 0)
- return true;
- return false;
- }
复制代码 除了比较两个字符串对象的大小,也可能比较一个字符串对象和一个字符串的大小,这里只以重载 > 举例。
- bool MyString::operator>(char *str) {
- if ((this->str == NULL) || (str == NULL))
- {
- cout << "存在空字符串,无法比较" << endl;
- exit(-1);
- }
- if (strcmp(this->str, str) > 0)
- return true;
- return false;
- }
复制代码
- 说明:比较两个字符串对象大小,以及比较字符串对象和字符串大小时,一定要先判断字符串是否指向 NULL,否则可能访问非法内存,导致段错误。
二、MyString 类完备代码
- #include <iostream>#include <string.h>using namespace std;// 界说一个 MyString 类class MyString{ friend istream& operator>>(istream &in, MyString &obj); friend ostream& operator<<(ostream &out, MyString obj);private: // 字符串的长度 int size; // z字符串首元素地址 char *str;public: // 构造函数 MyString(); MyString(char *str); MyString(const MyString &obj); // 析构函数 ~MyString(); // 获取字符串的长度 int Size(); char& operator[](int index); MyString& operator=(MyString &obj); MyString& operator=(char *str); bool operator>(MyString &obj); bool operator==(MyString &obj); bool operator<(MyString &obj); bool operator>(char *str);};MyString::MyString() {
- size = 0;
- str = NULL;
- }
- MyString::MyString(char *str) {
- size = strlen(str);
- // 多加一个放 \0
- this->str = new char[size + 1];
- // strcpy 会拷贝 \0
- strcpy(this->str, str);
- }
- MyString::MyString(const MyString &obj) {
- size = obj.size;
- this->str = new char[size + 1];
- strcpy(str, obj.str);
- }
- MyString::~MyString() {
- if (str != NULL)
- {
- delete [] str;
- str = NULL;
- }
- }
- int MyString::Size() {
- return size;
- }
- // 打印字符串,重载 << 运算符
- ostream& operator<<(ostream &out, MyString obj)
- {
- out << obj.str;
- return out;
- }
- // 输入字符串,重载 >> 运算符
- istream& operator>>(istream &in, MyString &obj)
- {
- // 如果字符串不为空,先指向空
- if (obj.str != NULL)
- {
- delete [] obj.str;
- obj.str = NULL;
- }
- // 定义一个临时变量存放键盘输入的值
- char temp[1024] = "";
- in >> temp;
- obj.size = strlen(temp);
- obj.str = new char[obj.size + 1];
- strcpy(obj.str, temp);
- return in;
- }
- char &MyString::operator[](int index) {
- // 先判断是否为空
- if (NULL == str)
- {
- cout << "字符串为空,无法操作" << endl;
- exit(-1);
- }
- // 判断索引是否越界
- if (index >=0 && index <size)
- {
- return str[index];
- }
- else
- {
- cout << index << "越界" << endl;
- exit(-1);
- }
- }
- MyString &MyString::operator=(MyString &obj) { // 先判断左值是否为空,非空要先开释 if (str != NULL) { delete [] str; str = NULL; } // 将右变对象的值拷贝给左边对象,深拷贝 size = obj.size; str = new char[size + 1]; strcpy(str, obj.str); return *this;}MyString& MyString::operator=(char *str) { // 先判断左值是否为空,非空要先开释 if (this->str != NULL) { delete [] this->str; this->str = NULL; } // 将右变对象的值拷贝给左边对象,深拷贝 size = strlen(str); this->str = new char[size + 1]; strcpy(this->str, str); return *this;}bool MyString::operator>(MyString &obj) { if ((str == NULL) || (obj.str == NULL)) { cout << "存在空字符串,无法比较" << endl; exit(-1); } if (strcmp(str, obj.str) > 0) return true; return false;}bool MyString::operator==(MyString &obj) { if ((str == NULL) || (obj.str == NULL)) { cout << "存在空字符串,无法比较" << endl; exit(-1); } if (strcmp(str, obj.str) == 0) return true; return false;}bool MyString::operator<(MyString &obj) { if ((str == NULL) || (obj.str == NULL)) { cout << "存在空字符串,无法比较" << endl; exit(-1); } if (strcmp(str, obj.str) < 0) return true; return false;}bool MyString::operator>(char *str) {
- if ((this->str == NULL) || (str == NULL))
- {
- cout << "存在空字符串,无法比较" << endl;
- exit(-1);
- }
- if (strcmp(this->str, str) > 0)
- return true;
- return false;
- }
- int main(){ cout << "------------------- 重载<< ------------------" << endl; MyString str1 = "hello world!"; cout << str1 << endl; // 得到字符串的长度 cout << "size = " << str1.Size() << endl; cout << "------------------- 重载>> ------------------" << endl; MyString str2; cout << "请输入一个字符串(不带空格):"; cin >> str2; cout << str2 << endl; cout << "------------------- 重载[] ------------------" << endl; MyString str3 = "hello"; cout << str3[4] << endl; str3[1] = 'E'; cout << str3 << endl; cout << "------------------- 重载= ------------------" << endl; MyString str4; MyString str5; str5 = str4 = "hello human"; cout << str4 << endl; cout << str5 << endl; cout << "------------------- 重载比较运算符 ------------------" << endl; MyString str6, str7; cout << "请输入两个字符串:"; cin >> str6 >> str7; if (str6 > str7) cout << str6 << "大于" << str7 << endl; else if (str6 == str7) cout << str6 << "即是" << str7 << endl; else cout << str6 << "小于" << str7 << endl;}
复制代码
- ------------------- 重载<< ------------------
- hello world!
- size = 12
- ------------------- 重载>> ------------------
- 请输入一个字符串(不带空格):helloworld
- helloworld
- ------------------- 重载[] ------------------
- o
- hEllo
- ------------------- 重载= ------------------
- hello human
- hello human
- ------------------- 重载比较运算符 ------------------
- 请输入两个字符串:hallo hello
- hallo小于hello
复制代码 三、其它知识点补充
1.不发起重载 && 和 ||
不要重载 && 和 || ,因为用户无法实现 && 和 || 的短路特性。
- class Complex {
- public:
- int flag;
-
- // 构造函数
- Complex(int flag) {
- this->flag = flag;
- }
- // 重载 += 运算符
- Complex &operator+=(Complex &complex) {
- this->flag = this->flag + complex.flag;
- return *this;
- }
- // 重载 && 运算符
- bool operator&&(Complex &complex) {
- return this->flag && complex.flag;
- }
- };
- int main() {
- Complex complex1(0); //flag 0
- Complex complex2(1); //flag 1
- if (complex1 && (complex1 += complex2)) {
- cout << "真!
- " << endl;
- } else {
- cout << "假!" << endl;
- }
- return 0;
- }
复制代码
- 说明
- 对象complex1的 flag 变量值为0,按原理来说,执行的效果应该为 "“假!” ,但这里的效果却为 “真!”;
- 因为在执行if (complex1 && (complex1 += complex2))的时候,(complex1 += complex2)会先触发operator+=(Complex &complex)函数的调用,从而将运算效果 1 赋值给 complex1 的 flag 导致最终的条件为 (1 && 1),因此效果为 “真!”;
- 所以,我们重载 && 运算符的时候 没法实现其短路特性。
其它不能重载的运算符:. :: .* ?: sizeof。
2.智能指针
智能指针可以帮助我们省略一部分内存操纵,通过在外包裹一层外壳,间接主动实现堆区空间的开释等操纵。
- class Data {
- private:
- int num;
- public:
- Data() {
- cout << "Data的无参构造" << endl;
- }
- Data(int num) {
- this->num = num;
- cout << "Data的有参构造 num=" << num << endl;
- }
- void showData() {
- cout << "num=" << num << endl;
- }
- ~Data() {
- cout << "Data的析构函数" << endl;
- }
- };
- class SmartPoint {
- private:
- Data *sp;
- public:
- SmartPoint() : sp(NULL) {}
- SmartPoint(Data *sp) {
- this->sp = sp;
- }
- SmartPoint(const SmartPoint &ob) {
- this->sp = new Data;
- *sp = *ob.sp;
- }
- ~SmartPoint() {
- delete sp;
- }
- Data *operator->() {
- return sp;
- }
- Data &operator*() {
- return *sp;
- }
- };
- int main() {
- SmartPoint bp(new Data(100));
- bp->showData();
- (*bp).showData();
- return 0;
- }
复制代码
- Data的有参构造 num=100
- num=100
- num=100
- Data的析构函数
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |