(八)C++基础之运算符重载(二)

1.1、关于运算符的使用规则

请参考我的上一篇文章:(七)C++基础之运算符重载(一)

1.2、双目运算符和单目运算符重载

所谓的双目运算符和单目运算符指的是他对应的参数多少,双目运算符就意味着存在两个参数,单目运算符就意味着存在一个参数。

1、双目运算符:

#include <iostream>

using namespace std;

class Complex
{
public:
	Complex(int real, int imaginary)
	{
		this->real = real;
		this->imaginary = imaginary;
	}

	void print(void)
	{
		cout << this->real << "+" << this->imaginary << "i" << endl;
	}

	Complex  operator+(Complex &c2)
	{
		Complex temp(0, 0);
		temp.real = this->real + c2.real;
		temp.imaginary = this->imaginary + c2.imaginary;

		return temp;
	}
private:
	int real; //实数
	int imaginary; //虚数
};

int  main(void)
{
	Complex c1(1,2);
	Complex c2(1, 2);
	Complex c3(0, 0);

	c3 = c1 + c2;
	c3.print();
	return 0;
}

运算结果:

在这里插入图片描述
2、单目运算符左++和右++:

左++,我们一般都是这样写:

	int a;
	++a;

甚至可以这样:

	++++++a;

关于++a,是先将a自增1,然后在将这个值处理。

所以我们想要实现左++,那么必须满足上面两种情况,其实我们通过 ++++++a; 可以推断出**++a** 返回的是自己本身,可以使用引用的方式来定义,接下来我们实现复数的左++。

代码如下:


#include <iostream>

using namespace std;

class Complex
{
public:
	Complex(int real, int imaginary)
	{
		this->real = real;
		this->imaginary = imaginary;
	}

	void print(void)
	{
		cout << this->real << "+" << this->imaginary << "i" << endl;
	}

	Complex  operator+(Complex &c2)
	{
		Complex temp(0, 0);
		temp.real = this->real + c2.real;
		temp.imaginary = this->imaginary + c2.imaginary;

		return temp;
	
	}

	Complex &operator++()
	{
		this->real++;
		this->imaginary++;

		return *this;
	}

private:
	int real; //实数
	int imaginary; //虚数
};


int  main(void)
{

	Complex c1(1, 2);
	Complex c2(1, 2);
	Complex c3(0, 0);

	c3 = c1 + c2;

	c3.print();

	++c3;

	c3.print();

	++++++c3;

	c3.print();

	return 0;
}

运行结果如下:
在这里插入图片描述

重点解释一下这个函数:

	Complex &operator++()
	{
		this->real++;
		this->imaginary++;

		return *this;
	}

由于他是单目运算符,所以我并没有进行传参,至于为什么要返回本身,是因为要满足 ++++++a 这种连续计算的功能,如果不返回本身,那么接下来的那个 **++**肯定无法运行。运行结果也很好的展示可以这样多次累加。

右++的写法如下:

	int a = 0;
	a++;

他的功能是先拿a的值去处理,处理完之后再对a进行自增1,那他能支持多次运算么?答案是不能。
在这里插入图片描述

在这里编译器已经进行报错了,可是另一个问题出现了,左++和右++都是使用++,那么该如何区分呢?

这时候就不得不提一下占位符,可以通过占位符的方式区分,右++需要提供一个占位符来让便一起同识别,你要重载的是右++。

代码如下:



#include <iostream>

using namespace std;

class Complex
{
public:

	friend ostream &operator<<(ostream &os, const Complex &c1);
	Complex(int real, int imaginary)
	{
		this->real = real;
		this->imaginary = imaginary;
	}

	void print(void)
	{
		cout << this->real << "+" << this->imaginary << "i" << endl;
	}

	Complex  operator+(Complex &c2)
	{
		Complex temp(0, 0);
		temp.real = this->real + c2.real;
		temp.imaginary = this->imaginary + c2.imaginary;

		return temp;
	
	}

	Complex &operator++()
	{
		this->real++;
		this->imaginary++;

		return *this;
	}

	const Complex operator++(int)
	{
		Complex temp(this->real,this->imaginary);

		this->real++;
		this->imaginary++;

		return temp;
	}

private:
	int real; //实数
	int imaginary; //虚数
};

ostream &operator<<(ostream &os, const Complex &c1)
{
	os << c1.real << "+" << c1.imaginary << "i";
	return os;
}

int  main(void)
{

	Complex c1(1, 2);
	Complex c2(1, 2);
	Complex c3(0, 0);

	c3 = c1 + c2;

	cout << c3++ << endl;

	cout << c3 << endl;

	return 0;
}

运行结果:
在这里插入图片描述

为了能够时刻显示右++的效果,我重载了<<这个运算符的函数,下一小节我们再讲这个,现在来看一下,这样就和普通的右++功能一样了,不能多次累加了。
在这里插入图片描述

我来讲一下这个函数:

	const Complex operator++(int)
	{
		Complex temp(this->real,this->imaginary);

		this->real++;
		this->imaginary++;

		return temp;
	}

增加一个const就是为了限制不能修改,也就是不能多次累加,括号里面的int就是占位符,他没有什么功能,主要是为了系统辨别右++而已,因为右++是先将值返回给语句处理,然后在则增1,所以临时定一个变量,保存自增前的值,将值返回,然后本身自增1。

1.3、<<和>>的重载

<<左移运算符在C++中重载为cout的输出,这个重载在上一小节我们实现过。我们通过如下:

cout << "hello world";

可以知道他传入的参数需要两个,第一个为cout,他的类型是 ostream,所以我们就可以实现这个左移重载函数了。
在这里插入图片描述
在上一小节,我们实现的是输出复数的值,如下:

ostream &operator<<(ostream &os, const Complex &c1)
{
	os << c1.real << "+" << c1.imaginary << "i";
	return os;
}

因为我们可以连续输出的,所以返回引用本身,可以多次输出,在第二个参数我为什么会增加一个 const ,我在这里说明一下,从安全级别低到高是可以兼容的,但是如果从安全级别高到低,那是不兼容的,而且这只是一个输出函数,我也不允许你修改我里面的值,所以加了个 const

可以看到,我将这个重载函数卸载类外,因为如果卸载类里面,他默认第一个参数this,你改不了,如下:

	ostream &operator<<(ostream &os)
	{
		return os;
	}

那么你在写成 cout << c3 将会报错,除非你写成 c3 << cout,但是这样和我们的使用习惯相符,所有最终将其写在类的外面的全局函数。

右移操作符>>和左移操作符一样,只是他的类型是istream,在这里我就不举例了。

1.4、等号=运算符

其实这个等号=运算符我们不陌生,在使用拷贝函数的时候我们已经运用过了,请参考之前的文章,在这里我在强调一次,等号=运算符如果里面涉及到指针,然后开辟内存的,一定要记得使用深拷贝,否则容易导致内存泄漏而使程序奔溃。

1.5、[]运算符的重载

对于[],我们可以在数组中很常见,我们自定义一个类似数组的功能,来重载[]这个运算符,代码如下:


#include <iostream>

using namespace std;

class MyArray
{
public:
	MyArray(int size)
	{
		this->len = size;
		this->p = new int[size];

		if (this->p == NULL){
			cout << "new init" << endl;
		}
	}

	~MyArray()
	{
		if (this->p != NULL){
			delete this->p;
			this->p = NULL;
		}
	}

	int &operator[](int index)
	{
		return this->p[index];
	}

	int len; 
	int *p; 
};


int  main(void)
{
	MyArray array(5);

	array[3] = 10;

	for (int i = 0; i < 5; i++){
		array[i] = i;
	}

	cout << "array[3]:" << array[3] << endl;

	return 0;
}

运行结果:
在这里插入图片描述

对于该函数:

int &operator[](int index)
	{
		return this->p[index];
	}

最终是返回对应的引用作为左值来处理。

1.6、()运算符的重载

对于()小括号的重载,我们看一段代码:


#include <iostream>

using namespace std;


//平方
class Power
{
public:

	Power(int data)
	{
		this->my_power = data * data;
	}

	int get_power()
	{
		return this->my_power;
	}

	void operator()(int data)
	{
		this->my_power = data * data;
	}

private:
	int my_power;
};


int  main(void)
{
	Power p(10);

	cout << p.get_power() << endl;

	p(20);

	cout << p.get_power() << endl;

	return 0;
}

运行结果:
在这里插入图片描述

对于这个函数,第一个()代表重载的运算符,第二个是填入形参列表的。

void operator()(int data)
	{
		this->my_power = data * data;
	}

最终调用的 p(10); 是运行重载运算符的函数,而不是构造函数,其中如果使用 对象名() 将一个对象作为一个普通函数使用,称这种对象是仿函数或者伪函数。

1.7、&& 和 || 运算符的重载

对于这两个运算符,我们是不建议重载,因为他不会造成 短路 现象,何为 短路 现象,在&&该运算符下,如果第一个条件不成立,第二个判断条件将不会运行,还有||,如果第一个条件成立,第二个条件也不会运行,这和我们预期的结果不同,所以不建议使用。

我们来看一段代码:


#include <iostream>

using namespace std;


//平方
class Test
{
public:

	Test(bool b)
	{
		this->a = b;
	}

	bool operator&&(Test &another)
	{
		if ((this->a == true) && (another.a == true)){
			return true;
		}
		else{
			return false;
		}
	}

	Test &operator+(Test &another)
	{
		cout << "执行Test &operator+(Test &another)" << endl;
		
		return *this;
	}

private:
	bool a;
};


int  main(void)
{
	Test t1(false);

	Test t2(true);

	if (t1 && (t1+t2))

	return 0;
}

运行结果:
在这里插入图片描述

我们看到,当我初始化第一个条件参数为false时候,在&&运算中,还是会执行第二个判断条件,也就是和我们使用 && 平时的习惯不一致,和我们的预期不一样,所以不建议使用。

||的运算符和&&的运算符是一样的道理,在这里我就不举例了。

发布了29 篇原创文章 · 获赞 0 · 访问量 415

猜你喜欢

转载自blog.csdn.net/weixin_42547950/article/details/104355061