您的位置:首页 > 编程语言 > C语言/C++

C++ 运算符重载(1)

2015-08-14 16:32 501 查看

一 运算符重载概述

二 重载运算符的实现

1 作为成员函数重载运算符

A 双目运算符重载

B 单目运算符重载

2 作为全局(友元)函数重载运算符

A 双目运算符重载

B 单目运算符重载

三、重载的规则和原则:

-----------------------------------------------------------------------------------------------------------

一、运算符重载概述

运算符重载,就是对已有的运算符进行重新定义,赋予其另一个功能,以适应不同的数据类型,

即一个名字的运算符可以代表不同的运算操作。

例如,程序中可以利用“+”对整型数、单精度、双精度以及指针进行加法运算等,如:

int a=1+1; //对整型数加

double d=2.2+2.2; //对双精度加

int arr[10];

int *p=arr;

p=p+1; //对指针加 p指向了第二个元素

现在,若有一个自定义的复数类型Complex,有两个复数对象c1=(5+10i),c2=(10-0.5i),

能否直接 使用“+”进行两个复数对象相加,即如表达式c1+c2能够成立呢?

答案是:可以,但程序员必须对“+”重载,

因为对于内置类型C++自身已经帮这些类型做了+的重载,而这些新类型就需要我们自己去做。

二、重载运算符的实现

重载的运算符函数语法为:

Operator为关键字,专门用于定义重载的运算符函数,#代表要被重载的运算符。

<返回值类型> operator # (<形参列表>)

{

用户实现的相关操作在这里

}

例如:

Complex operator + (Complex &a, Complex &b)

{

相关的操作在这里实现;

}

此函数可以用来实现对两个Complex对象进行相加。

C++中,重载运算符可以采用两种方式实现:

A、将重载的运算符函数作为自定义类的成员函数;

B、将运算符函数作为全局函数,即,不作为任何类的成员。

但是,若运算符函数需要访问操作数对象的私有成员,则必须将运算符声明成操作对象类型的友元。

因此,常常将这种方式称为全局(友元)函数形式。

1、作为成员函数重载运算符

作为成员函数重载时,运算符函数内的参数个数一般比运算符操作数个数少一个。

因为,对于类的非静态成员函数,第一个参数默认为指向对象的this指针

(例外:++,--作为后置时,有一个参数)。

A、双目运算符重载

作为非static成员函数重载双目运算符,只需要给出运算符右边操作数,左操作数为隐含的this指针,其函数原型声明为:

<返回值类型> operator # (<类型>);

函数定义形式为:

<返回值类型>[<类名::>] operator #(<类型> &<参数>)



相关操作……



#为被重载的运算符,“<类型><参数>”用来描述运算符右边的操作数,运算符重载函数的定义可以放在类体内也可以同其他成员函数一样放到类体外。

案例:使用成员函数来重载operator+ -运算符。

// 成员函数重载.cpp : Defines the entry point for the console application.
/*
使用成员函数来重载operator + -运算符。
*/

#include "stdafx.h"
#include "iostream"

using namespace std;

class Complex
{
public:
Complex(double r = 0.0, double i = 0.0) :real(r), imag(i){}

Complex operator +(Complex& c)<span style="white-space:pre">					</span><span style="font-family: Arial, Helvetica, sans-serif;">//重载运算符加号+,在类内声明和实现</span>
{
return Complex(real + c.real, imag + c.imag);
}	<span style="white-space:pre">					</span>
Complex operator -(const Complex& c);<span style="white-space:pre">				</span>//<span style="font-family: Arial, Helvetica, sans-serif;">在类内声明类外实现</span>
void ShowC();
friend ostream& operator <<(ostream& os, const Complex &c);<span style="white-space:pre">	</span><span style="font-family: Arial, Helvetica, sans-serif;">//重载运算符<<</span>

private:
double real, imag;					<span style="white-space:pre">	</span>//实部、虚部
};

Complex Complex::operator-(const Complex &c)
{
return Complex(real - c.real, imag - c.imag);<span style="white-space:pre">			</span>//注意返回值类型
}

void Complex::ShowC()
{
cout << "(" << real << " ," << imag << "i)" << endl;
}

ostream& operator <<(ostream& os, const Complex& c)
{
os << "(" << c.real << " ," << c.imag << "i)";
return os;
}

int _tmain(int argc, _TCHAR* argv[])
{

Complex c1(10, 5);
Complex c2(10, -5);
Complex c3, c4;

c3 = c1 + c2;
c4 = c1 - c2;

c3.ShowC();
c4.ShowC();

cout << c3 << endl;

return 0;
}



B、单目运算符重载

作为类的非静态成员函数重载单目运算符,一般不需要参数(后置++,--除外),

运算符的左操作数由函数隐含this指针提供,即运算符的前置用法。

函数的声明语法为:

<返回值类型> operator # ();

<pre name="code" class="cpp">// 成员函数重载.cpp : Defines the entry point for the console application.
/*
使用成员函数来重载operator 单目运算符取反运算符-。
*/

#include "stdafx.h"
#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& c); 		//重载双目运算符运算符减号-, 双目运算一个参数
Complex operator -()				//重载单目运算符取反-,单目运算没有参数
{
return Complex(-real, -imag);
}
friend ostream& operator <<(ostream& os, const Complex &c);

private:
double real, imag;				//实部、虚部
};

Complex Complex::operator-(const Complex &c)
{
return Complex(real - c.real, imag - c.imag);	//注意返回值类型
}

ostream& operator <<(ostream& os, const Complex& c)
{
os << "(" << c.real << " ," << c.imag << " i)";
return os;
}

int _tmain(int argc, _TCHAR* argv[])
{

Complex c1(10, 5);
Complex c2(10, -5);
Complex c3, c4;

c3 = -c1;				//调用单目运算符取反-
c4 = c1 - c2;			<span style="white-space:pre">	</span>//调用双目运算符相减-

cout << c3 << endl;
cout << c4 << endl;

return 0;
}





2、作为全局(友元)函数重载运算符

A、双目运算符重载

用全局(友元)函数来实现双目运算符重载时,需要两个函数,

函数声明语法为:

[friend]<返回值类型> operator # (<类型1>[<左参数>],<类型2>[<左参数>]);

运算符函数实现形式为:

< 返回值类型> operator # (<类型1>[<左参数>],<类型2>[<左参数>])

{

相关操作

}

B、单目运算符重载

用全局(友元)函数实现单目运算符重载时,需要给出一个参数,并且该参数的类型必须是类、结构、枚
举或它们的引用类型。

它重载的是运算符前置的用法,对于后置的++,--要增加第二个参数int,以和前置++,--区别。

函数声明的语法为:

[friend] <返回值类型> operator # (<类型>[<右参数>]);

其中,#代表被重载的运算符,<右参数>描述的是运算符右边的操作数。

实例双目与单目

// 成员函数重载.cpp : Defines the entry point for the console application.
/*
<span style="white-space:pre">	</span>使用友元函数来重载 双目目运算符== 和!=
*/

#include "stdafx.h"
#include "iostream"

using namespace std;

class Complex
{
public:
Complex(double r = 0.0, double i = 0.0) :real(r), imag(i){}

friend bool operator ==(const Complex &c1,const Complex &c2);	//友元重载双目运算符
friend bool operator !=(const Complex &c1, const Complex &c2);
friend Complex operator -(Complex& c);				//友元重载单目运算符取反-
friend ostream& operator <<(ostream& os, const Complex &c);	//重载运算符<<

private:
double real, imag;
};

bool operator ==(const Complex &c1,const Complex &c2)
{
return (c1.real == c2.real) && (c1.imag == c2.imag);
}

bool operator !=(const Complex &c1, const  Complex &c2)
{
return !(c1 == c2);
}

Complex operator -(Complex &c)
{
return Complex(-c.real, -c.imag);
}

ostream& operator <<(ostream& os, const Complex& c)
{
os << "(" << c.real << " ," << c.imag << "i)";
return os;
}

int _tmain(int argc, _TCHAR* argv[])
{

Complex c1(10, 5);
Complex c2(10,-5);
Complex c3(10,-5);
Complex c4;

cout << "c1等于c2吗?" << (c1 == c2);<span style="white-space:pre">	</span>//记得给加括号,因为==的优先级低于<<
cout << endl;
cout << "c1不等于C2吗?" << (c1 != c2);
cout << endl;
cout << "c2等于c3吗?" << (c2 == c3);
cout << endl;

c4 = - c1;
cout << c4 << endl;

return 0;
}



三、重载的规则和原则:

虽然在重载运算符时,可以象重载普通函数那样具有很大的灵活性,但也要遵循一定的规则和原则,这样才能正确重载运算符。总结如下:

1、不能改变运算符的的操作个数;

2、不能改变运算符的优先级;

3、 运算符重载不改变运算符的结合性;

4、 应该使重载的运算符函数的功能类似于该运算符作用于基本数据类型时所实现的功能;

5、只能对已有运算符重载,不能创建新的运算符;

6、 重载的运算符函数不能有默认函数,否则就改变了运算符参数的个数,与前面第三点有点矛盾;

7、 重载的运算符必须至少与一个用户自定义类型的对象一起使用,其参数至少应有一个是类的对象(或类对象
的引用)。

8、用于类对象的运算符一般必须重载,但是有两个例外,取地址运算符”&”,赋值运算符”=”不必重载。

编译器为每个类提供默认的”&”运算符函数和”=”运算符函数。

9、 重载的运算符函数可以是类的成员函数,也可以是全局(友元)函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: