北大MOOC第五周001:全面的MyString

题目地址http://cxsjsxmooc.openjudge.cn/2019t3sprintw5/001/

实战中学习,你觉得自己基础掌握的不错,是骡子是马show me the code,还是不行。自己在写vector和string的过程中才慢慢真正了解了C++的一些功能,以前都是只知道这些东西,但是不知道有啥用。

目前所用到的知识点:

1、C++中各种构造函数的不同和用处

2、不同操作符重载时的异同

3、友元函数在其中的使用

4、strlen和sizeof的区别

对本题的总结: 

1、对=的重载,需要注意判断是否把自己赋值给了自己;且需要返回引用。原因是:

在C++赋值运算符原本的特性中,赋值运算符返回的是左侧的引用,这样(a=b)=c就意味着先执行了(a=b)这个函数,然后返回了a的引用,a的引用还可以被赋值为c。如果不是返回的引用,那么返回值就是一个临时变量,不能被赋值!!!!!

所以自己在写的时候也要返回引用!!!

2、对()的重载,不能返回数组,要返回类的对象!

    如果返回数组,因为在函数内部要new出一个空间复制原来的数据,但是new后不会再自己释放。它不是类的对象,会造成内存泄露!!!!返回类的对象就可以了。
    但是这样使用new其实还存在一个问题,就是即如果我想通过这样的下标修改某一块的值时不行,因为是两块内存。不能实现string那样的功能。  

2、对+的重载,函数返回值类型不用设为引用,并且注意参数的前后顺序,这里不是加减法,a+b和b+a不一样

3、对+=的重载,函数返回值的类型必须为引用,并且函数内要返回*this。

因为mys+="abc"这句话,相当于是mys.operator(+=)("abc"),要想作用到mys上,必须返回当前对象*this的引用。这和+不一样,+返回的值并不是左值的引用

//#include 
#include 
using namespace std;
//这里,如果传入的s是个空指针,是会报错的,所以vs现在常常提醒用这些函数不安全
//int strlen(const char * s)
//{
//	int i = 0;
//	for (; s[i]; ++i);
//	return i;
//}
//void strcpy(char * d, const char * s)
//{
//	int i = 0;
//	for (i = 0; s[i]; ++i)
//		d[i] = s[i];
//	d[i] = 0;
//
//}
//int strcmp(const char * s1, const char * s2)
//{
//	for (int i = 0; s1[i] && s2[i]; ++i) {
//		if (s1[i] < s2[i])
//			return -1;
//		else if (s1[i] > s2[i])
//			return 1;
//	}
//	return 0;
//}
//void strcat(char * d, const char * s)
//{
//	//所以说strlen求的是到/0的长度,不是整个数组的长度!!!sizeof才是整个数组的长度
//	int len = strlen(d);
//	//这里一开始还没有反应过来!!牛逼d+len就是d数组的末尾元素\0
//	strcpy(d + len, s);
//}
class MyString
{
	// 在此处补充你的代码
	size_t len;
	char* str = nullptr;
public:
	MyString(const char* s)
	{
		//bug1 ==写成了=。。。。。。。。。
		if (s == nullptr)
			return;
		len = strlen(s);
		str = new char[len + 1];
		strcpy(str, s);
		//bug4 写'\0'或者0都行,但是有一处写成了'/0'......
		str[strlen(s)] = '\0';

	}
	MyString()
	{
		len = 0;
		str = nullptr;
	}
	~MyString()
	{
		//一定得判断str是否是空,要不删除一个空指针应该是不行的吧
		if (str)
			delete[]str;
	}
	MyString(const MyString& mys)
	{
		if (mys.str == nullptr)
			return;
		else
		{
			len = strlen(mys.str);
			str = new char[len + 1];
			strcpy(str, mys.str);
		}
	}
	//为什么不加friend只能有一个参数,而加了后就可以有两个参数了?
//因为对cout<<1;这句话,实际是operator<<(cout,1),也就是说<<本来是需要两个参数的。如果把<<重载成一个类的成员函数,则参数减1,其中的一个参数就是类对象本身。加了friend后该函数就不是成员函数了,所以要有两个成员函数
	friend ostream& operator<<(ostream& cout, const MyString& s)
	{
		if (s.str != nullptr)
			cout << s.str;
		return cout;
	}
	MyString& operator=(const MyString& mys)
	{
		if (mys.str == str)
			return *this;
		else
		{
			//先把原来的空间给清除掉
			if (str)
				delete[]str;
			len = strlen(mys.str);
			str = new char[len + 1];
			strcpy(str, mys.str);
		}
		return *this;
	}
	//这个+和+=的函数主体不是一样的吗??
	MyString operator+(const MyString& mys)
	{
		//这个判断必须要有吧。。
		if (mys.str == nullptr)
			return *this;
		MyString tempmys;

		tempmys.len =len + strlen(mys.str);
		tempmys.str = new char[tempmys.len + 1];
		//先把原来的赋值给strtemp
		strcpy(tempmys.str, str);
		strcat(tempmys.str, mys.str);
		return tempmys;
	}
	//bug 2 注意顺序。。。这不是加减法!!!重载的成意思是字符串的拼接,所以*this在前面,s在后面
	MyString operator+(const char* s)
	{
		MyString mys(s);
		return *this + mys;
	}
	friend MyString operator+(const char* s,  const MyString& rhs)
	{
		//存在问题??????????
		//明白了,因为这里传入的rhs是常引用,而上面重载的+不是常引用,cao
		//MyString mys;
		//mys = rhs + s;
		//return mys;

		MyString mys(s);
		return mys + rhs;
	}
	//bug 3 注意,+=返回的是引用,因为mys+="abc"这句话,相当于是mys.operator(+=)("abc"),要想作用到mys上,必须返回当前对象*this的引用
	MyString& operator+=(const char* s)
	{
		MyString mys(s);
		*this = *this + mys;
		return *this;
	}

	//这里不能返回数组,因为这样的话,自己要new出一个空间复制原来的数据,但是new后不会再自己释放,它不是类,不会造成内存泄露!!!!
	//但是这样又会存在一个问题,即如果我想通过这样的下标修改某一块的值时不行,因为是两块内存  
	MyString operator()(int i, int j)
	{
		MyString mys;
		mys.len = j;
		char* temps = new char[j+1];
		int start = 0;
		for (start = 0; start < j; start++)
			temps[start] = str[i + start];
		temps[start] = 0;
		mys.str = temps;
		return mys;
	}

	int operator<(const MyString& rhs)
	{
		if (strcmp(str, rhs.str) < 0)
			return true;
		else
			return false;
	}
	int operator==(const MyString& rhs)
	{
		if (strcmp(str, rhs.str) == 0)
			return true;
		else
			return false;
	}
	int operator>(const MyString& rhs)
	{
		if (strcmp(str, rhs.str) > 0)
			return true;
		else
			return false;
	}
	//这里返回值要为引用
	char& operator[](int i)
	{
		return str[i];
	}
};


int CompareString(const void * e1, const void * e2)
{
	MyString * s1 = (MyString *)e1;
	MyString * s2 = (MyString *)e2;
	if (*s1 < *s2)
		return -1;
	else if (*s1 == *s2)
		return 0;
	else if (*s1 > *s2)
		return 1;
}
int main()
{
	MyString s1("abcd-"), s2, s3("efgh-"), s4(s1);
	MyString SArray[4] = { "big","me","about","take" };
	cout << "1. " << s1 << s2 << s3 << s4 << endl;
	s4 = s3;
	s3 = s1 + s3;
	cout << "2. " << s1 << endl;
	cout << "3. " << s2 << endl;
	cout << "4. " << s3 << endl;
	cout << "5. " << s4 << endl;
	cout << "6. " << s1[2] << endl;
	s2 = s1;
	s1 = "ijkl-";
	s1[2] = 'A';
	cout << "7. " << s2 << endl;
	cout << "8. " << s1 << endl;
	s1 += "mnop";
	cout << "9. " << s1 << endl;
	s4 = "qrst-" + s2;
	cout << "10. " << s4 << endl;
	s1 = s2 + s4 + " uvw " + "xyz";
	cout << "11. " << s1 << endl;
	qsort(SArray, 4, sizeof(MyString), CompareString);
	for (int i = 0; i < 4; i++)
		cout << SArray[i] << endl;
	//s1的从下标0开始长度为4的子串
	cout << s1(0, 4) << endl;
	//s1的从下标5开始长度为10的子串
	cout << s1(5, 10) << endl;
	return 0;
}

 

你可能感兴趣的:(MOOC,C++程序设计)