运算符重载
运算符重载背景:
在c++
语言中,运算符可直接拿来进行整数、小数等的运算,但这些运算对象都是c++
语言中的标准对象,这种情况能满足我们大多数的应用场景,但是,面对我们自定义的对象,运算符不能直接拿来使用,例如自己构造一个复数的类,默认情况下,c++
语言不支持复数运算,因此我们需要将运算符重载,使它们能够满足我们自定义的对象的运算。运算符重载的实质是函数重载,它提供了C++
的可扩展性,也是C++
最吸引人的特性之一。
运算符重载规则
C++
几乎可以重载全部的运算符,而且只能够c++
中已经有的
- 不能重载的运算符:“.”,“.*”,“::”,“?:”
- 重载之后运算符的优先级和结合性都不会改变
- 运算符重载是针对新数据类型的实际需要,对原有运算符进行适当改造。
- 例如
- 使复数类的对象可以使用“
+
”运算符实现加法- 使时钟类对象可以用“
++
”运算符实现时间增加1秒重载的两种形式
- 重载为类的非静态成员函数
- 重载为非成员函数
双目运算符重载为成员函数
重载为类成员的运算符函数定义形式:
函数类型 operator 运算符(形参)
{
·····
}
参数个数=源操作数个数-1(后置++、--除外)
当运算符重载为类的成员函数时,函数的参数个数比原来的操作数要少一个(后置单目运算符除外),这是因为成员函数用this指针隐式地访问了类的一个对象,它充当了运算符函数最左边的操作数。
双目运算符重载规则(重载为类的非静态成员函数)
- 如果要重载B为类成员函数,使之能够实现表达式
oprd1 B oprd2
其中oprd1
为A
类对象,则B
应被重载为A
类的成员函数,形参类
型应该是oprd2
所属的类型。- 经重载后,表达式
oprd1 B oprd2
相当于oprd1. operator B(oprd2)
举一个例子实现复数类加减法运算重载为成员函数
- 要求
- 将
+
、-
运算重载为复数类的成员函数- 规则
- 实部和虚部分别相加减
- 操作数
- 两个操作数都是复数类对象
示例代码:
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
//运算符 + 重载成员函数
Complex operator +(const Complex &c1)const;
//运算符 - 重载成员函数
Complex operator -(const Complex &c2)const;
void display() const; // 输出复数
private:
double real; // 复数实部
double imag;//复数虚部
};
Complex Complex:: operator +(const Complex &c1)const {
return Complex(real + c1.real, imag + c1.imag);
}
Complex Complex::operator - (const Complex &c2)const {
return Complex(real - c2.real, imag - c2.imag);
}
void Complex::display()const {
cout << "("<<real << "," << imag << ")" << endl;
}
int main(void)
{
Complex c1(4, 5), c2(2, 10), c3;
cout << "c1="; c1.display();
cout << "c2="; c2.display();
c3 = c1 - c2;//使用重载运算符完成复数减法
cout << "c3=c1-c2="; c3.display();
c3 = c1 + c2;//使用重载运算符完成复数加法
cout << "c3=c1+c2="; c3.display();
}
代码运行结果:
c1=(4,5)
c2=(2,10)
c3=c1-c2=(2,-5)
c3=c1+c2=(6,15)
请按任意键继续. . .
单目运算符重载为成员函数
因为++
--
参与运算时前置后置属于两种不同计算行为,在类内声明时函数名相同,怎样区分他们的功能呢?就是利用重载函数的区分原则即参数不同,下面详细介绍具体规则
前置单目运算符重载规则
- 如果重载函数U为类沉管函数,使之能够实现表达式
U oprd
,其中oprd
为A
类对象,则U
应被重载为A
类成员函数,无形参。- 经重载后
表达式U oprd
相当于oprd.operator U()
后置单目运算符重载规则
- 如果要重载
++
或--
为类的成员函数,使之能够实现表达式oprd++
或oprd--
,其中oprd
为A
类对象,则++
或--
应被重载为A类的成员函数,且具有一个int
类型形参- 经重载后,表达式
oprd++
相当于oprd.operator ++(0)
举一个时钟类例子来说明具体用法:
#include <iostream>
using namespace std;
class Clock {
public:
Clock(int hour = 0, int min = 0, int sec = 0);
void Show_Time();
//前置单目运算符重载
Clock operator ++();
//后置单目运算符重载
Clock operator ++(int);
private:
int hour, min, sec;
};
Clock::Clock(int hour, int min, int sec) {
if (0 <= hour && hour < 24 && 0 <= min && min < 60 && 0 <= sec && sec < 60)
{
this->hour = hour;
this->min = min;
this->sec = sec;
}
else {
cout << "Time Err" << endl;
}
}
void Clock::Show_Time() {
cout << hour << ":" << min << ":" << sec << endl;
}
Clock Clock::operator ++() {
sec++;
if (sec >= 60) {
sec -= 60;
min++;
if (min >= 60) {
min -= 60;
hour = (hour + 1) % 24;
}
}
return *this;
}
Clock Clock::operator ++(int) {
Clock old = *this;
++(*this);
return old;
}
int main(void)
{
Clock myClock(23, 59, 59);
cout << "first time: ";
myClock.Show_Time();
cout << "++myClock time: ";
(++myClock).Show_Time();
cout << "myClock++ time: ";
(myClock++).Show_Time();
cout << "after myClock++ time: ";
myClock.Show_Time();
return 0;
}
代码运行结果:
first time: 23:59:59
++myClock time: 0:0:0
myClock++ time: 0:0:0
after myClock++ time: 0:0:1
请按任意键继续. . .
运算符重载为非成员函数
应用场景
- 左值为非类成员,参与与类的运算(实数与复数类的运算)
- 左值为类成员,但该类属于类库中的成员,或者我们没有办法为类添加重载函数的情况
运算符重载为非成员函数的规则
- 函数的形参依自左至右次序排列的各操作数
- 重载为非成员函数时
- 参数个数=原操作数个数(后置
++
--
除外)- 至少有一个自定义类型的参数
- 后置单目运算符
++
和--
的重载函数,形参列表中要增加一个int
,但不必写形参名。- 如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元
- 双目运算符
B
重载后,表达式oprd1 B oprd2
等同于operator B(oprd1,oprd2)
- 前置单目运算符
B
重载后,表达式B oprd
等同于operator B(oprd)
- 后置单目运算符
++
--
重载后表达式oprd B
相当于operator B(oprd,0)
例子重载Complex
的加减法和“<<
”运算符为非成员函数
- 将
+
、-
(双目)重载为非成员函数,并将其声明为复数类的友元,两个操作数都是复数类的常引用- 将
<<
(双目)重载为 非成员函数,并将其声明为复数类的友元,它的左操作数是std::ostream
引用,有操作数为复数类的常引用,返回std::ostream
引用,用以支持下面形式的输出:cout<<a<<b;
该输出调用的是:
operator<<(operator<<(cout,a),b)
代码如下:
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
//运算符 + 重载成员函数
friend Complex operator +(const Complex &c1,const Complex &c2);
//运算符 - 重载成员函数
friend Complex operator -(const Complex &c1, const Complex &c2);
friend ostream& operator <<(ostream &out,const Complex &c);
void display() const; // 输出复数
private:
double real; // 复数实部
double imag;//复数虚部
};
Complex operator +(const Complex &c1, const Complex &c2) {
return Complex(c1.real+c2.real, c1.imag + c2.imag);
}
Complex operator - (const Complex &c1, const Complex &c2){
return Complex(c1.real - c2.real, c1.imag - c2.imag);
}
ostream& operator <<(ostream &out, const Complex &c) {
out << "(" << c.real << "," << c.imag << ")";
return out;
}
void Complex::display()const {
cout << "(" << real << "," << imag << ")" << endl;
}
int main(void)
{
Complex c1(4, 5), c2(2, 10), c3;
cout << "c1="; c1.display();
cout << "c2="; c2.display();
c3 = c1 - c2;//使用重载运算符完成复数减法
cout << "c3=c1-c2="; c3.display();
c3 = c1 + c2;//使用重载运算符完成复数加法
cout << "c3=c1+c2="; c3.display();
cout << "c3:" << c3 << endl;
return 0;
}
代码运行结果:
c1=(4,5)
c2=(2,10)
c3=c1-c2=(2,-5)
c3=c1+c2=(6,15)
c3:(6,15)
请按任意键继续. . .