一,目标
此次目的很明显,实现string类中的主要方法,包括:构造函数,拷贝构造函数,+,+=运算符的重载等。
在实际的面试中,关于string的问题会很多,因此自己实现一遍很有必要。
二,代码实现
1,首先看声明
#pragma once
#include<iostream>
using namespace std;
class MyString
{
MyString(const char* s = NULL); //普通构造函数
MyString(const MyString& x); //拷贝构造函数
inline size_t Size() const //获得str长度
{
return strlen(str);
}
MyString& operator=(const MyString& other); //赋值运算符重载
MyString operator+(const MyString& x);
MyString& operator+=(const MyString& x);
bool operator==(const MyString& x);
friend ostream& operator<<(ostream& out, const MyString& x); //<<的重载
~MyString();
private:
char* str;
};
2,具体实现
//如果x==NULL,则申请一个字节用来存放结束符,之所以这样做,是担心直接cout一个NULL的str
MyString::MyString(const char* x)
{
if (x == NULL)
{
str = new char[1];
*str = '\0';
}
else
{
str = new char[strlen(x) + 1]; //此处加1是为了放上结束符
strcpy(str, x);
}
}
MyString::MyString(const MyString& x)
{
str = new char[strlen(x.str) + 1];
strcpy(str, x.str);
}
//这里之所以要检测是否自赋值是因为如果不检测,直接将原始的str清空后,就没办法再给自己复制了
//因为它们指向同一块区域
MyString& MyString::operator=(const MyString& other)
{
if (this == &other) //防止自赋值
return *this;
delete[] str;
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
}
MyString MyString::operator+(const MyString& x)
{
MyString temp;
temp.str = new char[strlen(str) + strlen(x.str) + 1];
strcpy(temp.str, str);
strcat(temp.str, x.str);
return temp;
}
MyString& MyString::operator+=(const MyString& x)
{
//+=,此时可以调用已重载的+运算符
*this = *this + x;
return *this;
}
bool MyString::operator==(const MyString& x)
{
return strcmp(str, x.str) == 0 ? true : false;
}
ostream& operator<<(ostream& out, const MyString& x)
{
out << x.str;
return out;
}
MyString::~MyString()
{
delete[] str; //直接删除
}
3,测试代码
void test()
{
//首先会调用拷贝构造函数,给字符串“hello”创建一个临时对象,然后再掉用赋值运算符给x赋值
MyString x("hello");
//调用拷贝构造函数,也可以写为:MyString y(x);
MyString y = x;
cout << y << endl;
MyString z = ",world!";
//调用+运算符,先产生一个x与z的临时对象,然后调用拷贝构造函数给z赋值,析构临时对象,
z = x + z;
cout << z << endl;
}
注意以上运行还不会成功,需要加入指令:#pragma warning(disable:4996)
这是因为c++认为strcpy等函数不安全,所以已经选择弃用,加入这句指令,就是指忽略相应
的警告。
3,运行结果
注意此处的调试信息在上面的代码中并没有添加,只是为了测试我的猜想
测试是从z的定义那里产生的,
3.1,首先调用构造函数,用字符串给z赋值
3.2 调用加号运算符,生成temp的临时对象,使我不解的是此处为什么没有调用构造函数呢?
然后调用拷贝构造函数生成temp的拷贝对象返回,接着析构temp;
3.3,接着调用等号运算符,把这个拷贝对象再赋给z;
3.4,析构z,x,y
4,总结
1,其实还有很多string类的功能没有实现,以我的理解,只要理解了底层的实现细节,对自己以后使用相应的方法是很有帮助的,毕竟是自己完成过
2,to_str()方法其实就是直接返回 (const char*) str;
3,拷贝构造函数与=构造函数的不同便是,拷贝构造函数是一种特殊的构造函数,所以它是用来初始化一个对象的,而=运算符则是用来给一个已经存在的对象重新赋值
4,每个类都提供了默认的构造函数,拷贝构造函数,析构函数,=运算符,之所以还要自己重新定义,这就设计浅拷贝与深拷贝的问题了,关于这点,有兴趣的可以自己去了解