我们首先来看看C++库中的string类有什么功能。
string s1("hel");
string s2("lo");
string s3;
s3 = s1 + s2;
cout << s3 << endl;
我们就先看看上面这些例子,首先我们可以用一个字符串给s1对象初始化,我们可以用+号连接两个字符串,同时我们还可以用=号直接给s3对象赋值,最后还可以用cout直接输出这个对象中的字符串。
我们自己写个类来实现这些功能。
实现这些功能需要注意的
1、要注意字符串的拷贝,深拷贝。
2、注意内存的动态分配和释放。
3、运算符重载的使用。
现在我们就来看看怎么编写这些功能,看代码。
#include <iostream>
#pragma warning(disable:4996) //由于在vs2015使用strcpy会报错,所以加了这一句话
using namespace std;
class MyString
{
public:
MyString(char *s);
MyString(const MyString &s); //拷贝构造函数
MyString(); //不带参数的构造函数
~MyString(); //析构函数
MyString& operator=(const MyString &s); //=号运算符重载
MyString operator+(const MyString &s);//+号运算符重载
char operator[](int i);//[]运算符重载
bool operator<(const MyString &s);//<运算符重载
bool operator>(const MyString &s);//>运算符重载
bool operator==(const MyString &s);//==运算符重载
bool operator!=(const MyString &s);//!=运算符重载
private:
char *str;
//友元函数
friend ostream& operator<<(ostream &out, MyString &s);//重载左移运算符
friend istream& operator >> (istream &in, MyString &s); //重载右移运算符
};
//不带参数的构造函数
MyString::MyString()
{
this->str = new char[1];
str[0] = '\0';
}
//带一个参数的构造函数
MyString::MyString(char *s)
{
str = new char[strlen(s) + 1];
strcpy(this->str, s);
}
//拷贝构造函数
MyString::MyString(const MyString &s)
{
str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
}
//析构函数
MyString::~MyString()
{
if (this->str != NULL)
{
delete[] this->str;
}
}
//+号运算符重载
MyString MyString::operator+(const MyString &s)
{
MyString p;
p.str = new char[strlen(this->str) + strlen(s.str) + 1];
strcpy(p.str, this->str);
strcat(p.str, s.str);
return p;
}
//=号运算符重载
MyString& MyString::operator=(const MyString &s)
{
if (this == &s)
{
return *this;
}
if (this->str != NULL)
{
delete[] this->str;
}
this->str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
return *this;
}
//[]运算符重载
char MyString::operator[](int i)
{
int len = strlen(this->str) - 1;
if (i > len)
{
return ('\0');
}
else
{
return (this->str[i]);
}
}
//<运算符重载
bool MyString::operator<(const MyString &s)
{
int ret;
ret = strcmp(this->str, s.str);
if (ret < 0)
return true;
else
return false;
}
//>运算符重载
bool MyString::operator>(const MyString &s)
{
int ret;
ret = strcmp(this->str, s.str);
if (ret > 0)
return true;
else
return false;
}
//==运算符重载
bool MyString::operator==(const MyString &s)
{
int ret;
ret = strcmp(this->str, s.str);
if (ret == 0)
return true;
else
return false;
}
//!=运算符重载
bool MyString::operator!=(const MyString &s)
{
int ret;
ret = strcmp(this->str, s.str);
if (ret != 0)
return true;
else
return false;
}
//左移运算符重载
ostream& operator<<(ostream &out, MyString &s)
{
out << s.str;
return out;
}
//右移运算符重载
istream& operator>>(istream &in, MyString &s)
{
char p[50];
in.getline(p, 50);
s = p;
return in;
}
int main()
{
MyString m1("hello");
MyString m2("world");
MyString m3;
m3 = m1 + " " + m2;
cout << "m3 = " << m3 << endl;
MyString m4(m3);
cout << "m4 = " << m4 << endl;
cout << "m1[1] = " << m1[1] << endl;
cout << (m1 < m2) << endl;
cout << (m1 > m2) << endl;
cout << (m1 == m3) << endl;
system("pause");
return 0;
}
这里主要讲解的是拷贝构造函数、赋值运算符重载、+号运算符重载和[]运算符重载的写法。
拷贝构造函数
MyString::MyString(const MyString &s)
{
str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
}
拷贝构造函数的第一个参数时这个类的一个引用,拷贝构造函数主要完成两个任务:①是给类中的str动态分配空间,用来容纳传入的s对象中的str字符串。②将s对象中的str拷贝到被初始化对象的str中。
赋值函数(=号运算符重载)
MyString& MyString::operator=(const MyString &s)
{
if (this == &s)
{
return *this;
}
if (this->str != NULL)
{
delete[] this->str;
}
this->str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
return *this;
}
首先要判断这两个对象是否相同,如果相同就返回这个对象本身,如果不同就得判断原本的对象中给str分配的空间有没有被释放,如果没有就得将其内存释放,然后重新分配一个能够容纳用于赋值的对象中str的空间。然后再将这个str拷贝到被赋值的str中。
[]运算符重载
char MyString::operator[](int i)
{
int len = strlen(this->str) - 1;
if (i > len)
{
return ('\0');
}
else
{
return (this->str[i]);
}
}
在写[]运算符重载的时候我们要注意下标的越界问题,所以我们得先判断要取出的下标是否越界,如果越界我就让其返回一个空字符。否则我们就返回相应的元素。
+号运算符重载
MyString MyString::operator+(const MyString &s)
{
MyString p;
p.str = new char[strlen(this->str) + strlen(s.str) + 1];
strcpy(p.str, this->str);
strcat(p.str, s.str);
return p;
}
我们定义一个局部对象,用来存放连接后的字符串,首先要给它分配一个能够容纳两个字符串的空间,然后用strcpy将第一个字符串复制到p中,再用strcat连接这两个字符串。