运算符重载

  • 运算符重载

    对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时导致不同的行为

    • 运算符重载规则

      (1)C++中的运算除少数几个之外,全部可以进行重载,而且只能重载C++中已经由的运算符;

      (2)重载之后运算符的优先级和结合性都不会变;

      (3)运算符重载时针对新类型数据的实际需要,对原有的运算符进行适当的改造。重载的功能应当与原有功能向类似,不能改变原运算符的员操作对象个数,同时至少有一个是自定义类型;

      注:C++规定“.” “::” “?” “*”不能被重载

    返回类型 operator 运算符(参数表)
    {
          函数体
    }//重载类的成员函数的一般语法;
    返回类型 operator 运算符(形参表)
    {
         函数体
    }//重载类非成员函数,可以标注为友元;
    

    注:当运算符重载为类的成员函数时,参数的个数比原来的操作数少一个(自加自减除外);当运算符重载为非成员函数时,参数个数与原操作数相同。前者第一操作数会被作为函数调用的目的对象无需出现在参数表中,函数体可以直接访问第一个操作数的成员;而后者运算符所有操作必须显式通过参数传递。

  • 运算符重载为成员函数

    运算符重载实质上就是函数重载,重载为成员函数,就可以自由访问本类的数据成员。实际使用时,总是通过该类的某个对象来访问重载的运算符。

    如果为双目运算符则左操作数必须为本类的对象,由this指针而右操作数可以由其他数据类型隐含转换,用参数表来传递;

    oprd1 B oprd2其中前者为A类的对象,B为A中的成员函数,该函数只有一个形参,形参的类型时oprd2的类型(有时也可能由其他数据类型隐含转换而来)oprd1 B oprd2等价于oprd1.B(oprd2);

    对于前置单目运算符,“U”和“-”,如果要重载为A类的成员函数,U oprd等价于oprd.U();

    对于后置“++”和”- -“oprd++或者oprd- -运算符重载为A类的成员函数需要带有一个int类型的形参,oprd++等价于oprd.++(0);

    #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 c2) const;	//运算符+重载成员函数
    	Complex operator - (const Complex c2) const;	//运算符-重载成员函数
    	void display() const;	//输出复数
    private:	//私有数据成员
    	double real;	//复数实部
    	double imag;	//复数虚部
    };	
    
    Complex Complex::operator + (const Complex c2) const 
    {	//重载运算符函数实现
    	return Complex(real + c2.real, imag + c2.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() {	//主函数
    	Complex c1(5, 4), c2(2, 10), c3;	//定义复数类的对象
    	cout << "c1 = "; c1.display();
    	cout << "c2 = "; c2.display();
    	c3 = c1 - 1;	//使用重载运算符完成复数减法
    	//c3=c1.operator -(1);
    	cout << "c3 = c1 - c2 = "; c3.display();
    	c3 = c1 + c2;	//使用重载运算符完成复数加法
    	cout << "c3 = c1 + c2 = "; c3.display();
    	c3 = c2 + 2.0;	
    	cout << "c3 = c1 + c2 = " ;c3.display();
    	c3 = 2 + c2;	//运行错误
    	cout << "c3 = c1 + c2 = " ;c3.display();
    	//c3 = 2.0 + c2;	
    	//cout << "c3 = c1 + c2 = " ;c3.display();
    	//c3 = 2 + c2;	
    	//cout << "c3 = c1 + c2 = " ;c3.display();
    	return 0;
    }
    //8_2.cpp
    #include <iostream>
    using namespace std;
    class Clock	{	//时钟类声明定义
    public:	//外部接口
    	Clock(int hour = 0, int minute = 0, int second = 0);
    	void showTime() const;
    	Clock operator ++ ();	//前置单目运算符重载
    	Clock operator ++ (int);	//后置单目运算符重载,有无参数 
    private:	//私有数据成员
    	int hour, minute, second;
    };
    
    Clock::Clock(int hour/* = 0 */, int minute/* = 0 */, int second/* = 0 */) {	//构造函数,带初始值的默认构造函数不加初始值 
    	if (0 <= hour && hour < 24 && 0 <= minute && minute < 60 && 0 <= second && second < 60) {
    		this->hour = hour;
    		this->minute = minute;
    		this->second = second;
    	} else
    		cout << "Time error!" << endl;
    }
    
    void Clock::showTime() const {	//显示时间函数
    	cout << hour << ":" << minute << ":" << second << endl;
    }
    
    Clock  Clock::operator ++ () {	//前置单目运算符重载函数
    	second++;
    	if (second >= 60) {
    		second -= 60;
    		minute++;
    		if (minute >= 60) {
    			minute -= 60;
    			hour = (hour + 1) % 24;
    		}
    	}
    	return *this;
    }
    
    Clock Clock::operator ++ (int) {	//后置单目运算符重载
    	//注意形参表中的整型参数
    	Clock old = *this;
    	++(*this);	//调用前置“++”运算符
    	return old;
    }
    
    int main() {
    	Clock myClock(23, 59, 59);
    	cout << "First time output: ";
    	myClock.showTime();
    	
    	cout << "Show myClock++++:    ";
    	(myClock++++).showTime();
    
    	
    	(myClock).showTime();
    	
    	
    	cout << "Show ++++myClock:    ";
    	(++++myClock).showTime();
    
    	return 0;
    }
    

    注:对于函数参数表中未使用的参数,C++允许不给出参数名

  • 运算符重载为非成员函数

    运算符也可以重载为非成员函数,运算所需要的操作数都需要通过函数的形参表来传递,在形参表中形参从左到右的顺序就是运算符操作数的顺序。如果需要访问运算符参数对象的私有成员,可以将该函数声明为类的友元函数(也可以不,在不需要访问保护或者私有成员时)。

    对于双目运算符B,如果要实现 oprd1 B oprd2,其中oprd1 和 oprd2中只要有一个具有自定义类型,就可以将B重载为非成员函数,函数的形参为oprd1 和 oprd2。经过重载之后,表达式oprd1 B op-d2就相当于函数调用operator B(oprd1,oprd2)。 对于前置单目运算符U,如“一”(负号)等,如果要实现表达式U oprd,其中 oprd 具有自定义类型,就可以将U重载为非成员函数,函数的形参为oprd。经过重载之后,表达式 U oprd 相当于函数调用operator U(oprd)。 对于后置运算符十十和一一,如果要实现表达式oprd ++或oprd --,其中 oprd为自定义类型,那么运算符就可以重载为非成员函数。这时函数的形参有两个,一个是 oprd,另一个是int类型形参。第二个参数是用于与前置运算符函数相区别的。重载之后,表达式 oprd ++和 oprd--就相当于函数调用operator ++(oprd,0)和 operator -- (oprd,0)。

    #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);**		***//运算符<<重载***
    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;
    }
    
    int main() {	//主函数
    	Complex c1(5, 4), c2(2, 10), c3;	//定义复数类的对象
    	cout << "c1 = " << c1 << endl;
    	cout << "c2 = " << c2 << endl;
    	c3 = c1 - c2;	//使用重载运算符完成复数减法
    	cout << "c3 = c1 - c2 = " << c3 << endl;
    	c3 = c2 + 2.0;	
    	cout << "c3 = c1 + c2 = " << c3 << endl;
    	c3 = c2 + 2;	
    	cout << "c3 = c1 + c2 = " << c3 << endl;
    	c3 = 2.0 + c2;	
    	cout << "c3 = c1 + c2 = " << c3 << endl;
    	c3 = 2 + c2;	
    	cout << "c3 = c1 + c2 = " << c3 << endl;
    	return 0;
    }
    

    注:<<操作数是ostream类型的引用,ostream是cout类型的一个基类

两种运算符重载方式的对比(必须使用非成员函数的时候):

(1)要重载的操作符的第一个操作数不是可以更改的类型,例如上例中“<<”运算符的第一个操作数的类型为ostream,是标准库的类型,无法向其中添加成员函数。 (2)以非成员函数形式重载,支持更灵活的类型转换。例如例 8-3 中,可以直接使用 5.0+cl,因为Complex的构造函数使得实数可以被隐含转换为Complex类型。这样 5.0+cl 就会以operator+(Complex(5.0),c1)的方式来执行,c1+5.0也一样,从而支持了实数和复数的相加,很方便也很直观;而以成员函数重载时,左操作数必须具有 Complex类型,不能是实数(因为调用成员函数的目的对象不会被隐含转换),只有右操作数可以是实数(因为右操作数是函数的参数,可以隐含转换)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值