【运算符重载】——重载实现复数、string类

文章目录

  • 1、实现一个简单的运算符重载
  • 2、运算符重载实现复数类
    • 1、加法运算符重载
    • 2、输入输出运算符重载
    • 3、比较运算符
  • 3、运算符重载实现String类
    • 1、加法运算符重载
    • 2、比较运算符重载
    • 3、输入输出运算符重载

引言:在模板中,我们定义了如下的sum函数

template<typename T>
T sum(T a,T b)
{
	return a+b;
}

如果是正常的数据类型还可以运算,但是遇到对象相加了怎么办呢?
那么就引出我们今天所要讨论的内容——运算符重载

1、实现一个简单的运算符重载

1、运算符重载的作用
就像我们引言中所描述的一样,运算符重载的作用就是使得自定义类型和内置类型相同的逻辑

2、运行机制

主要是通过函数实现的。
【举个栗子】

int main()
{
	int arr[] = { 1,22,32,45,67,46,69 };
	int len = sizeof(arr) / sizeof(arr[0]);
	for (CInt i = 0; i < len; i++)
	{
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
	return 0;
}

在上面的这个程序逻辑里面,CIn是一个对象,需要我们实现比较运算符的重载、++运算符的重载、中括号运算符重载等。

1、比较运算符的重载
因为运算符重载是通过函数实现的,所以在设计的时候我们就需要考虑函数的函数名、参数、返回值、函数体这四个元素。

  • 函数名:operator关键字加上要重载的运算符
  • 参数:this指针接收的是左操作数,右操作数通过实参到形参传递的方式来获取
  • 返回值:如果是比较的话就是一个bool表达式
  • 函数体:就实现具体的逻辑过程
bool operator <(int rhs)
{
	return value < rhs;
}

2、++运算符的重载
分析
因为++运算符的重载还分为前置加加和后置加加。所以为了区分,我们使用一个标志,将参数是int的设置成为后置加加,没有参数的表示前置加加。
然后再来分析常量中后置加加的逻辑,他是一个先赋值后加加的过程。所以对应到对象里面,我们就应该首先拿到临时量的备份,再加加。
实现如下:

const CInt operator++(int)
	{
		CInt tmp(*this);
		value++;
		return tmp;
	}

前置加加就是先加加再赋值的过程,所以返回的是自加变量的本身,实现如下:

const CInt operator++()
{
	value++;
	return *this;
}

3、中括号运算符
分析
这是是一个双目运算符, arr[i]和i[arr]表示的含义都是一样的,左操作数接收的是一个对象,右操作数接收形参int型的指针为第一个元素的地址。返回的是内存单元的本身,就是int&
实现如下

	int& operator[](int* parr)
	{
		return parr[value];
	}

2、总结
函数的实现分为两种方式

  1. 在类中this指针接收左操作数
  2. 在类外左右操作数通过形参接收(并且一定要记住在类外实现的函数一定要在类中设置成函数友元才能访问私有的成员变量)

总体实现实现一个简单的运算符重载

2、运算符重载实现复数类

首先,我们先来编写一个简单的复数运算,代码如下:

class CComplex
{
public:
	CComplex(int r = 0,int i =0)
		:mreal(r)
		,mimage(i)
	{}
	void show() { cout << "real:" << mreal << "image:" << mimage << endl; }
private:
	int mreal;
	int mimage;
int main()
{
	CComplex comp1(10, 10);
	CComplex comp2 = comp1 + 10;
	CComplex comp3 = 10 + comp1;	
	if(comp2 > comp3)
	{
		std::cout<> comp2;
	std::cout<

1、加法运算符重载

1、对象+对象
分析
去寻找comp1这个对象里面有没有一个加号方法把comp2当做一个实参进来 comp1.operatpr+(comp2) 加法运算符的重载函数,看似在做运算,实质上是做成员方法的调用。写成这样也可CComplex comp3 = comp1.operator+(comp2);
代码实现:

CComplex operator+(const CComplex& src)//引用接收另一个复数类对象
	{
		CComplex comp;//定义一个新对象
		comp.mreal = tmreal + src.mreal;
		comp.mimage = mimage + src.mimage;
		return comp;
	}

上述代码优化后的结果如下:

CComplex operator+(const CComplex& src)//引用接收另一个复数类对象
	{
		return CComplex(mreal + src.mreal,mimage+src.mimage);
	}

2、对象+变量
分析
加号运算符的逻辑功能,加号逻辑完成过后,左右操作数的值是不会改变的,是存放在一个临时量里面的。相应的,在类中就应该返回的是常临时对象。类类型的返回是有临时对象的生成,所以不用再加引用
实现

const CComplex operator+(int rhs)
{
	return CComplex(mreal + rhs, mimage);
}

3、变量+对象
分析
不能放在类中处理,因为类中this指针接收的是左操作数是一个对象。如果写在类外的话就是一个_cdcal调用约定,没有this指针。就写两个参数即可,另外还要注意在类中还有一个与其对应的友元函数。返回值就是临时对象的常量
代码实现

const CComplex operator+(int lhs,const CComplex& rhs)
{
	return CComplex(lhs + rhs.mreal, rhs.mimage);
}

2、输入输出运算符重载

1、输出流运算符
分析
当我们要输出对象的信息时,就必须重载输入输出运算符。该运算符是在类外定义的,所以要在私有成员变量里面定义友元函数。

  • 是一个双目运算符。左操作数是一个输出流,右操作数是一个复数的对象
  • 输出流参数:输出流在生成对象的时候一定要用引用来生成,因为输出流和输出缓冲区有关,一个程序只能够分配一个输出流缓冲区,所以给出引用让out也变成这个输出缓冲区一个绑定的别名就可以了。
  • 返回值:为了保证连续输出,所以返回值也是一个输出流的引用。
std::ostream& operator<<(std::ostream& out, const CComplex& src)
{
	out << "mreal:" << src.mreal << "mimage:" << src.mimage << std::endl;
	return out;
}

2、输入流运算符
分析
因为输入一定会改变对象的值,和输出流运算符不同的是右操作数复数类对象不能使用const
代码实现

std::istream& operator>>(std::istream& in,CComplex& src)
{
	in >> src.mreal >> src.mimage;
	return in;
}

3、比较运算符

1、比较运算符重载函数(==)

	bool operator==(const CComplex& src)
	{
		return (mreal == src.mreal) && (mimage == src.mimage);
	}

2、比较运算符重载函数(>)

	bool operator >(const CComplex& src)
	{
		return (mreal > src.mreal) ||( (mreal > src.mreal) && (mimage > src.mimage));
	}

总体代码参考实现一个复数类

3、运算符重载实现String类

首先,我们先来编写一个简单的字符串运算,代码如下:

int main()
{
	std::String str1("hello");
	std::STtring str2 = str1 + "world";
	std::String str3 = "hi" + str1;
	std::String str4 = str1 + str2;

	if (str1 < str2)
	{
		std::cout << str1 << std::endl;
	}
	if (str3 != str4)
	{
		std::cout << str4 << std::endl;
	}
	return 0;
}

1、加法运算符重载

1、对象+字符串的重载函数
在类中实现

const String operator+(const char* rhs)
	{
		//首先开辟能容纳对象+字符串的空间
		char* tmp = new char[strlen(pstr) + strlen(rhs) + 1]();
		//将原对象内容拷贝到新开辟的空间中
		strcpy_s(tmp, strlen(pstr) + 1, pstr);
		//将传入的字符串参数连接到原对象字符串后面
		strcat(tmp, rhs);

		String str(tmp);
		delete[] tmp;
		return str;

	}

2、对象+对象的重载函数
在类中实现

const String operator+(const String& rhs)
	{
		char* tmp = new char[strlen(pstr) + strlen(rhs.pstr) + 1]();
		strcpy_s(tmp, strlen(pstr) + 1, pstr);
		strcat(tmp, rhs.pstr);

		String str(tmp);
		delete[] tmp;
		return str;
	}

3、字符串+对象的重载函数
在类外实现,传入两个参数

const String operator+(const char* lhs, const String& rhs)
{
	char* tmp = new char[strlen(lhs) + strlen(rhs.pstr) + 1]();
	strcpy_s(tmp, strlen(lhs) + 1, lhs);
	strcat(tmp, rhs.pstr);

	String str(tmp);
	delete[] tmp;
	return str;
}

2、比较运算符重载

字符串之间的比较主要是使用strcmp系统函数实现。

	bool operator>(const String& str)
	{
		return strcmp(pstr, str.pstr) > 0;
	}
	bool operator<(const String& str)
	{
		return strcmp(pstr, str.pstr) < 0;
	}
	bool operator==(const String& str)
	{
		return strcmp(pstr, str.pstr) == 0;
	}

3、输入输出运算符重载

//输出运算符重载
std::ostream& operator<<(std::ostream& out, const String rhs)
{
	out << rhs.pstr;
	return out;
}

//输入运算符重载
std::ostream& operator>>(std::ostream& in, String rhs)
{
	in << rhs.pstr;
	return in;
}

整体代码参考运算符重载实现String类

你可能感兴趣的:(c++)