模拟string
基础代码:
class String
{
private:
char* str;
public:
String(const char* p = NULL) : str(NULL)
{
if (p != NULL)
{
str = new char[strlen(p) + 1];
strcpy(str, p);
}
else
{
str = new char[1];
*str = '\0';
}
cout << "Create String: " << this << endl;
}
~String()
{
if (str != NULL)
{
delete[]str;
}
str = NULL;
cout << "destroy String: " << this << endl;
}
模拟输出(<<)
ostream& operator<<(ostream& out) const
{
if (str != NULL)
{
out << str;
}
return out;
}
这个函数是类的成员函数,有两个形参:实际上函数参数可以理解为:
ostream& operator<<(const String* const this, ostream& out);
为了避免使用友元函数,需要在类外在写一个输出函数
ostream& operator<<(ostream& out, const String& s)
{
s << out;
return out;
}
这样可以避免友元的使用:
int main(void)
{
String s1("hello");
cout << s1 << endl;
return 0;
}
拷贝构造函数
String(const String& s)
{
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
cout << "Copy Create: " << this << endl;
}
int main(void)
{
String s1("hello");
String s2(s1);
return 0;
}
赋值运算符重载
String& operator =(const String& s)
{
if (this != &s)
{
delete[] str;
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
}
cout << this << " operator= " << &s << endl;
return *this;
}
注意点:防止自赋值,防止内存泄漏,防止浅拷贝
int main(void)
{
String s1("hello");
String s2;
s2 = s1;
return 0;
}
加法运算符重载
因为返回时要构造一个对象,所以重载一个构造函数,作为私有成员。
private:
char* str;
String(char* p, int)
{
str = p;
}
对象和对象相加
String operator+(const String& s) const
{
char* p = new char[strlen(this->str) + strlen(s.str) + 1];
strcpy(p, this->str);
strcat(p, s.str);
cout << "Object + Object" << endl;
return String(p, 1);
}
int main(void)
{
String s1("hello");
String s2("world");
s1 = s1 + s2;
return 0;
}
对象和字符串相加
String operator +(const char* s) const
{
char* p = new char[strlen(this->str) + strlen(s) + 1];
strcpy(p, this->str);
strcat(p, s);
cout << "Object + char*" << endl;
return String(p, 1);
}
int main(void)
{
String s1("hello");
String s2;
s2 = s1 + "world";
return 0;
}
字符串和对象相加
可以借助上面写的函数,简单实现字符串与对象相加
String operator+(const char* p, const String& s)
{
cout << "char* + Object" << endl;
return String(p) + s;
}
int main(void)
{
String s1("hello");
String s2;
s2 = "world" + s1;
return 0;
}
移动构造函数
即实现资源的转移
String(String&& s)
{
cout << "move copy construct: " << this << endl;
str = s.str;
s.str = NULL;
}
String fun()
{
String s2("world");
return s2;
}
int main(void)
{
String s1;
s1 = fun();
return 0;
}
在程序执行到return s2; 时,就会调用移动构造函数,将 s2的资源转移,然后置为NULL。
运行结果:
移动赋值函数
String& operator=(String&& s)
{
if (this != &s)
{
s.str = Release(s.str);
}
cout << this << " move operator=: " << &s << endl;
return *this;
}
char* Release(char* p)
{
char* old = str;
str = p;
return old;
}
String fun()
{
String s2("world");
return s2;
}
int main(void)
{
String s1;
s1 = fun();
return 0;
}
详解
在程序运行到return s2; 时移动构造出一个将亡值,然后析构 s2;
fun()结束时返回调用点,调用移动赋值函数
调用完 Release() 实现资源的交换,移动赋值完成。
运行结果: 由于运行了几次,地址发生了变化,不影响查看。。
图示
- 移动构造将亡值,指向 s2申请的空间,析构 s2
- 拿将亡值移动赋值 s1
- Release()函数实现资源的交换,使 s1指向原 s2申请的空间,将亡值指向原 s1申请的空间,函数结束,将亡值析构,s1成功拿到 原s2的资源。
完整代码
#include<iostream>
#include<cstdlib>
#include<string.h>
using namespace std;
class String
{
private:
char* str;
String(char* p, int)
{
str = p;
}
public:
String(const char* p = NULL) : str(NULL)
{
if (p != NULL)
{
str = new char[strlen(p) + 1];
strcpy(str, p);
}
else
{
str = new char[1];
*str = '\0';
}
cout << "Create String: " << this << endl;
}
~String()
{
if (str != NULL)
{
delete[]str;
}
str = NULL;
cout << "destroy String: " << this << endl;
}
ostream& operator<<(ostream& out) const
{
if (str != NULL)
{
out << str;
}
return out;
}
String(const String& s)
{
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
cout << "Copy Create: " << this << endl;
}
String& operator =(const String& s)
{
if (this != &s)
{
delete[] str;
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
}
cout << this << " operator= " << &s << endl;
return *this;
}
String operator+(const String& s) const
{
char* p = new char[strlen(this->str) + strlen(s.str) + 1];
strcpy(p, this->str);
strcat(p, s.str);
cout << "Object + Object" << endl;
return String(p, 1);
}
String operator +(const char* s) const
{
char* p = new char[strlen(this->str) + strlen(s) + 1];
strcpy(p, this->str);
strcat(p, s);
cout << "Object + char*" << endl;
return String(p, 1);
}
String(String&& s)
{
cout << "move copy construct: " << this << endl;
str = s.str;
s.str = NULL;
}
String& operator=(String&& s)
{
if (this != &s)
{
s.str = Release(s.str);
}
cout << this << " move operator=: " << &s << endl;
return *this;
}
char* Release(char* p)
{
char* old = str;
str = p;
return old;
}
};
ostream& operator<<(ostream& out, const String& s)
{
s << out;
return out;
}
String operator+(const char* p, const String& s)
{
cout << "char* + Object" << endl;
return String(p) + s;
}
|