谭浩强第三版第10章运算符重载

1、运算符重载

重载——一名多用。同一个运算符,在不同的场合使用有不同的作用。

2、运算符重载的方法

定义一个重载运算符的函数。运算符重载实质上是函数的重载

一般格式:
函数类型 operator 运算符名称(形参表){对运算符的重载处理}

如:Complex operator +(Complex &c1,Complex &c2);

函数名是operator 运算符名称,即“operator +”,称:“operator +"重载了运算符”+“
参数是两个复数时系统调用重载函数。
普通的原函数:

Complex Complex::complex_add(Complex &c2){
	Complex c;
	c.real=real+c2.real;
	c.imag=imag+c2.imag;
	return c;
}

“+”重载函数:

Complex Complex::operator +(Complex &c2){
	Complex c;
	c.real=real+c2.real;
	c.imag=imag+c2.imag;
	return c;
}

更简练的写法:

Complex Complex::operator +(Complex &c2){
	return Complex(real+c2.real,imag+c2.imag):
}

3、重载运算符的规则

1、C++不允许用户定义新下运算符,只能对已有的C++运算符进行重载
2、C++运行重载的运算符。
表10.1 C++允许重载的运算符

双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)
关系运算符==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++(自增),–(自减)
位运算符(按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符=, +=, -=, *=, /= , % = , &=,
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),->*(成员指针访问),,(逗号),

不允许重载的5个运算符:

.(成员访问运算符)
.*(成员指针访问运算符)
::(域运算符)
sizeof(长度运算符)
?:(条件运算符)

前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和sizeof 运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。

3、重载不能改变运算符对象(操作数)的个数
4、重载不能改变运算符的优先级别
5、重载不能改变运算符的结合性
6、重载运算符 函数不能有默认的参数
7、重载的运算符必须和用户的自定义类型的对象一起使用,其参数至少应有一个是类对象。
8、用于类对象的运算符一般必须重载,但有两个例外,“=”和“&”(返回类对象再内存中的起始地址)不必用户重载
9、理论上,可以将一个运算符重载为执行任意 操作

4、运算符重载函数作为类成员函数和友元函数

对运算符重载的函数有两种:

  • 把重载函数作为类 成员函数;
  • 作为一个普通函数,在类中声明为友元函数。
    友元运算符重载函数:
class Complex{
public:
	....
	friend Complex operator +(Complex &c1,Complex &c2);//友元函数
	...
}
Complex operator +(Complex &c1,Complex &c2){//在类外定义的重载函数
	return Complex(c1,real+c2.real,c1.imag+c2.imag):
}

对于+运算,是需要两个操作数的,第一种方法定义重载时,有一个参数是隐含的,把this指针指向的对象的成员作为其中一个参数,所以该方法下函数参数只有一个;
而第二种方法是在类外定义的友元函数,就需要两个参数。

第一种方法的“+”左边的一定要Complex类对象,例如:c3=c2+c1;或c3=c1+4;如果是其他的类型或其他类的对象,就调用不到重载函数。
第二种方法在定义重载函数时,函数的参数类型任意,但在使用时,“+”左边的操作数类型要与第一个参数一致,“+”右边的操作数要和第二个参数类型一致。

  • C++规定,“=”、“[]”、“()”、“->”必须作为成员函数重载
  • "<<"、">>"、类型转化运算符函数不能定义为类成员函数,只能作为友元函数
  • 一般将单目运算符和复合运算符重载为成员函数
  • 一般将双目运算符重载为友元函数

5、重载双目运算符

双目运算符(二元运算符):2个参数。

class String{
	public:
		String(){p=NULL;}
		String(char *str);
		friend bool operator>(String & string1,String &string2);//声明运算符函数为友元函数
		void display();
	private:
		char *p;
};
String ::String(char *str){p=str;}
void String::display(){cout<<p;}
bool operatro>(String &string1,String &string2){//返回一个bool类型。
	if(strcmp(string1.p,string2.p)>0)
		return true;
	else return else;
}
int main(){
	String string1("Hello"),string2("Book");
	cout<<(string1>string2)<<endl;//
}

重载方法:先搭框架,逐步扩充,由简到繁,最后完善。边调试,边扩充。

6、重载单目运算符(只有一个操作数)

只有一个操作数,把重载函数重载为类中的成员函数,默认为this 指针指向的对象为唯一操作数。

7、重载流插入运算符“>>“和流提取运算符”<<"

istream &operator >>(istream &,自定义类 &);
ostream& operator<<(ostream &,自定义类&);

7.1重载流插入运算符"<<"

输出自己声明的类的对象的信息

ostream & operator<<(ostream & output,Complex & c){
	output<<"("<<c.real<<" +"<<c.imag<<"i)"<<enl;
	return output;
}

cout<<c3;//c3是Complex类,调用重载函数,输出(8+14i)
return output的作用:能连续向输出流插入信息,如:cout<<c3<<c2;cout<<c3调用重载函数后将cout的当前值返回,相当于cout(新值)<<c2,此时依旧满足调用重载函数的条件,所以可以让cout连续输出。

7.2重载流提取运算符">>"

istream& operator>>(istream & input,Complex &c){
	input>>c.real<<c.imag;
	return input;
}
cin>>c1>>c2;//连续输入3 6 4 -10,得到c1=(3+6i) c2=4+-10i)

8、有关运算符重载的归纳

使用运算符重载的具体做法:

  • 确定要重载哪个运算符,想应用到哪一个类。重载运算符只能把一个运算符用于一个指定的类,而不是所有类都可以适用。
  • 设计运算符重载函数和有关类。
  • 实际中,不要求最终用户自己取编写每一个运算符重载函数,有人事先把需要重载 运算符统一放在一个头文件里。
  • 使用者需要了解该头文件包含哪些运算符的重载,适用于那些类,有哪些参数。
  • 没有现成的就得自己设计,把设计好的保留下来。

9、不同类型数据间的转化

9.1标准类型间的转换

  • 隐式类型转换。由编译系统自动完成。
  • 显式类型转换。程序员指定的。
    显式类型转换的两种形式:类型名(数据),如:int(89.5);
    (类型名)数据。如:(int)89.5;

9.2用转换构造函数进行不同类型数据的转换。

转换构造函数:将一个其他类型的数据转换成一个类的对象。
(只有一个形参),

Complex(double r){real=r;imag=0;}//将double类型的参数转换成Complex类的对象,r为复数的实数,虚部为0
 Complex c1(3.5);//建立对象c1,由于只有一个参数,调用转换构造函数。
 Complex(3.6);//建立一个无名对象,合法但无法使用;
 c1=Complex(3.6);//建立一个无名对象,值为(3.6+0i),把这个无名对象的值赋给c1

“+”重载后,两边都是Complex对象作为操作数。如果要用它来将一个对象和浮点数,相加,可以利用转换构造函数将浮点数进行强制转换,c=c1+Complex(2.5);//合法;

使用方法:

  • 先声明一个类
  • 在类中定义一个只有一个参数 的构造函数,参数类型是需要转换 类型,在函数体中指定转换的方法
  • 在类的作用范围内可以使用以下形式进行类型转换。类名(指定类型的数据)。

9.3类型转换函数

作用:将一个类的对象转换成另一个类型的数据。
opertor 类型名(){
实现转换的语句
}

//将一个Complex类对象转换成一个double数,
operator double(){return real;}//返回double类型real的值。
  • 类型转换函数只能作为成员函数,转换的主体是本类的对象,不能作为友元函数或普通函数。
  • 隐式调用,如果运算符左右不符合,需要将double转换成对象时,系统自动调用,否则不调用。
  • 又称“类型转换运算符函数”,“类型转换运算符重载函数”
  • d1=d2+c1;
    首先,看重载+,”+“左为double类型,右为Complex类型。不符合。
    然后,发现有重载double,调用。
    完成。
  • c2=c1+d2,有转换构造函数和重载+(作为Complex类友元,即左侧一定要是Complex):
    首先,有重载+,判断:+左边是对象,满足;右边不是对象,不满足,不符合。
    再看是否有double重载,没有。
    最后去找转换构造函数,转换Complex(d2),建立临时的对象,此时符合重载+,调用重载+。

如果运算符函数重载为成员函数,第一个参数必须是本类 对象。当第一个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符“+”函数重载为类的成员函数,交换律不可用。
一般将双目运算符函数重载为友元函数,单目运算符则多重载为成员函数。
如果一定要将双目运算符重载为成员函数,第一个操作数又不是类对象时,只能再重载一个“+”函数,第一个参数为double类型,并重载为友元函数。
如果要使用类型转换函数,应删去“+”重载函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值