C++函数运算符重载

1、函数符号为什么要重载?
答:运算符重载就是赋予运算符多重含义。C++通过重新定义运算符,使它能够用于特定类的对象执行特定的操作(不然只能用于对基本类型的常量或变量之间的运算,而不能用于对象之间的运算),这便增强了C++语言的扩充能力。
2、哪些运算符需要重载,哪些不需要重载?
答:可以重载的运算符:

  • 算术运算符:+,-,*,/,%,++,–;
  • 位操作运算符:&,|,~,^,<<,>>
  • 逻辑运算符:!,&&,||;
  • 比较运算符:<,>,>=,<=,==,!=;
  • 赋值运算符:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=;
  • 其他运算符:[],(),->,(逗号运算符),new,delete,new[],delete[],->*。

不能重载的运算符:

  • ::(作用域)
  • .(成员运算符)
  • .*成员指针解引用
  • Sizeof(类型大小)
  • ? :三元运算符
  • Typeid 获取类型的信息(返回值类型typeinfo)

只能对已有的运算符进行重载,不能发明新的运算符;
不能对基本类型进行运算符重载(运算符重载中至少有一个类型是非基本类型);
不能改变运算符的运算特性;不能把一元的改成二元的;

3、为什么C语言不需要重载,而C++运算符需要重载?
答:这个本小白也没有找到具体解释,小白自己理解的为:C++是面向对象的语言,即不止需要对基本类型的常量和变量进行操作,还需要对对象进行操作,这就需要对基本类型的运算符赋予新的运算意义。而C语言中止运算符操作的对象也都是基本类型的常量或者变量,不需要赋予新的运算意义。

‘+’运算符进行重载

class Complex
{
public:
	Complex(int a, int b)
	{
		cout << "Complex(int a, int b)" << endl;
		_a = a;
		_b = b;
	}
	Complex operator+(const Complex& src)const
	{
		cout << "Complex operator+(const Complex& src)const"<<endl;
		int a = _a + src._a;
		int b = _b + src._b;
		return Complex(a, b);
	}
}
int main()
{
   	Complex c1(1, 2);
	Complex c2(2, 3);
	Complex c3 = c1 + c2;
}

图解:
在这里插入图片描述
‘-’ ‘||’ ‘&&’运算符重载及调用方法与上类似,这里只给出代码:

	Complex operator-(const Complex& src)const
	{
		int a = _a - src._a;
		int b = _b - src._b;
		return Complex(a, b);
	}
	bool operator &&(const Complex& src)const
	{
		return _a && src._a;
	}
	bool operator ||(const Complex& src)const
	{
		return _a|| src._a;
	}

下边我们来看一下前置加减和后置加减,解释都在代码注释中:

Complex& operator++ ()//前置++,加了之后再用
	{
		++_a;
		return *this;//这里是直接对this本身进行操作,没有额外的临时对象,所以可以返回引用
	}
	Complex operator ++(int)//后置++,先传值,再++(用了之后再加)
	{
		int tmp = _a;//记录++之前的值,我们要使用的就是这个临时量
		_a++;
		return Complex(tmp, _b);//此处不能返回引用,因为构造的是临时对象,出了函数之后就相当于野指针了
	}
	Complex& operator-- ()//前置--
	{
		--_a;
		return *this;
	}
	Complex operator --(int)//后置--,先传值,再--
	{
		int tmp = _a;//记录--之前的值
		_a--;
		return Complex(tmp, _b);//此处不能返回引用,因为构造的是临时对象,出了函数之后就相当于野指针了
	}

这里着重介绍输出和输入运算符重载:
先给代码

class Complex
{
public:
	friend ostream& operator <<(ostream& out, const Complex& src);
	friend istream& operator >>(istream& is, Complex& p);
}
ostream& operator <<(ostream& out, const Complex& src)//输出运算符重载
{
	out << src._a << "+" << src._b << "i" << endl;
	return out;
}
istream& operator >>(istream& in, Complex& p)//输入运算符重载
{
	in >> p._a;
	in >> p._b;
	return in;
}

输出和输入运算符为什么必须在类内定义,在类外实现?
我们先在类内实现来看一下:

class Complex
{
public:
   void operator<<(/*this*/ostream&out)
   {
      out<<_a<<"+"<<_b<<"i"<<endl;
   }
}
int main()
{
    Complex c1(1, 2);
   	c1.operator<<(/*this*/cout);
}

注意:<<是个一个双目运算符,即需要两个参数,在类内实现的话,第一个参数是this指针,这是默认的位置。不可改变,输出流在第二个参数,那么在类外使用时,就必须按照“ c1.operator<<(/*this*/cout);”这种方式来调用,为的就是把输出流放在第二位。

我们发现,这样调用的话非常不方便,如何才能像‘+’‘-’这样方便的使用呢?
要解决这个问题,我们首先要做的就是调换这两个参数的位置(因为类似cout<<c1这种输出,输出流都是在第一位的),但是这在类内是不可能实现的,因为系统默认this指针在第一位,不能调换,此时就必须在类外去实现这个操作。也就是这种:

ostream& operator <<(ostream& out, const Complex& src)//输出运算符重载
{
	out << src._a << "+" << src._b << "i" << endl;
	return out;
}

此时又有一个问题,为什么返回值必须是ostream& 而不能是void呢?
这是因为我们要实现运算符的连续输出,如果是void类:cout<<c1这是没有问题的,可以输出,但是cout<<c1<<endl;就会报错,不能连续输出。之前说过<<是一个双目运算符,那么它就需要两个参数,如果连续输出的话,后边输出的第一个参数就是前边的返回值,如果返回值为空,那么就缺少第一个参数,自然就不能连续输出,所以返回值类型必须为ostream&型,保留第一个参数。

总代码实现:

class Complex
{
public:
	Complex(int a, int b)
	{
		cout << "Complex(int a, int b)" << endl;
		_a = a;
		_b = b;
	}
	Complex operator+(const Complex& src)const
	{
		cout << "Complex operator+(const Complex& src)const"<<endl;
		int a = _a + src._a;
		int b = _b + src._b;
		return Complex(a, b);
	}
	Complex operator-(const Complex& src)const
	{
		int a = _a - src._a;
		int b = _b - src._b;
		return Complex(a, b);
	}
	bool operator &&(const Complex& src)const
	{
		return _a && src._a;
	}
	bool operator ||(const Complex& src)const
	{
		return _a|| src._a;
	}
	void operator<<(/*this*/ostream& out)//第一个是this指针,当前对象,第二个是输出流
	{
		out << _a << "+" << _b << "i" << endl;
	}
	Complex& operator++ ()//前置++
	{
		++_a;
		return *this;
	}
	Complex operator ++(int)//后置++,先传值,再++
	{
		int tmp = _a;//记录++之前的值
		_a++;
		return Complex(tmp, _b);//此处不能返回引用,因为构造的是临时对象,出了函数之后就相当于野指针了
	}
	Complex& operator-- ()//前置--
	{
		--_a;
		return *this;
	}
	Complex operator --(int)//后置--,先传值,再--
	{
		int tmp = _a;//记录--之前的值
		_a--;
		return Complex(tmp, _b);//此处不能返回引用,因为构造的是临时对象,出了函数之后就相当于野指针了
	}
	//friend void operator <<(ostream& out, const Complex& src);//这种没有返回值时,只能输出一个,如果连续输出,第二个要输出的就少了第一个参数
	friend ostream& operator <<(ostream& out, const Complex& src);
	friend istream& operator >>(istream& is, Complex& p);
private:
	int _a;//实部
	int _b;//虚部
};

//void operator <<(ostream& out, const Complex& src)
ostream& operator <<(ostream& out, const Complex& src)//输出运算符重载
{
	out << src._a << "+" << src._b << "i" << endl;
	return out;
}
istream& operator >>(istream& is, Complex& p)//输入运算符重载
{
	is >> p._a;
	is >> p._b;
	return is;
}
int main()
{
	string s1 = "aaaa";
	string s2 = "bbbbb";

	string s3 = s1 + s2;
	cout << s3 << endl;
	Complex c1(1, 2);
	Complex c2(2, 3);
	Complex c3 = c1 + c2;
	cout << c1 << c2 << endl;
	cout << c3;
	cin >> c1;
	if (c1 && c2)
	{
		cout << "all 0" << endl;
	}
	c1.operator<<(/*this*/cout);
	cout << c1<<c2;
	return 0;
}

在这里插入图片描述

附加内容:
在函数重载时,一般可以写成成员函数和全局函数两种,一般也都写成成员函数,这是因为编译器在解析到重载运算符的时候,会先去类的成员函数中找重载的成员函数,如果没有再去全局区找重载的全局函数。所以能写成成员函数就尽量写成成员函数。

附加内容参考:https://blog.csdn.net/uestclr/article/details/51126112.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值