运算符重载
在头文件中,如果函数在类声明的时候同时也定义了原型,则自动成为内联函数,这种句法适用于声明那些不会对其显示访问的对象进行修改的函数。2、非成员 重载运算符函数 原型格式(即友元函数,作为类的扩展接口的组成部分,类方法和友元只是表达类接口的两种不同机制):
以重载 + 为例,
其函数声明原型为
friend Time operate+(const Time & t1 ,const Time & t2);
以重载 * 为例,虽然 operate*()函数不是类成员函数,但它与成员函数的访问权限相同;
3.1、 重载 << 运算符时,最好用友元函数,因为
如果像重载 * 那样,则
cout << trip;
如果使用Time成员函数来重载<<,Time对象将是第一个操作数,就像使用成员函数*运算符那样,这意味着必须这样使用
trip <<cout;
这明显不是我们想要的,会让人迷惑,为改变这种做法,可以使用友元函数可以像下面这样重载函数运算符:
void operator<<(ostream & os,const Time & t)
{
os << t.hours<<" hours," <<t.minutes<< " minutes ";
}
这样,可以使用下面的语句:
cout << trip;
3.2、如上重载方法不允许如下使用:
cout << “trip time:”<< trip << " Tuesday\n";
即不能连用 << 运算符;因为cout << x << y 相当于 (cout << x ) << y;则cout<< x肯定返回的是ostream对象,因此,可以对友元函数采用如下做法,
ostream & operator << (ostream & os,const Time & t)
{
os << t.hours << " hours ," << t.minutes << " minutes";
return os;
}
注意,返回类型是ostream&,这意味着该函数返回ostream 对象的引用,则下面的语句:
cout << trip;
将被转化为如下的调用;
operator <<(cout,trip);
而该调用返回cout对象。
4、转换构造函数只用于从某种类型到类类型的转换,且只有接受一个参数的构造函数才能作为转换函数;
operatorComplex(double r){real=r;imag=0;} //转换构造函数
要进行相反的转换,必须使用特殊的C++运算符函数------转换函数;那么,如何创建转换函数呢?要转化为typename 类型,需要使用这种形式的转换函数
operator typeName();//转换类型函数
请注意以下几点:
# 转换函数必须是类方法;
# 转换函数不能指定返回类型;
# 转换函数不能有参数;
例如,转换为double类型的函数的原型如下:
operator double();
typeName 指出了要转换成的类型,因此不需要指定返回类型。转换函数是类方法意味着:他需要通过类对象来调用,从而告知函数要转换的值。因此,不需要参数。
将构造函数用于自动类型转换函数似乎是一项不错的特性。然而,当程序员拥有更丰富的c++经验时,将发现这种自动特性并非总是符合需要的,因为这会导致意外的类型转换。因此,c++新增了关键字 explicit ,用于关闭这种特性。
用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。
C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:
operator double( )
{
return real;
}
函数返回double型变量real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员real的值。请注意,函数名是operator double,这点是和运算符重载时的规律一致的(在定义运算符“+”的重载函数时,函数名是operator +)。
类型转换函数的一般形式为:
operator 类型名( )
{
实现转换的语句
}
在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。
从函数形式可以看到,它与运算符重载函数相似,都是用关键字operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的double型数据,而且还会把Complex类对象作为double型数据处理。
那么程序中的Complex类对具有双重身份,既是Complex类对象,又可作为double类型数据。Complex类对象只有在需要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。
[例10.9] 使用类型转换函数的简单例子。
- #include <iostream>
- using namespace std;
- class Complex
- {
- public:
- Complex( ){real=0;imag=0;}
- Complex(double r,double i){real=r;imag=i;}
- operator double( ) {return real;} //类型转换函数
- private:
- double real;
- double imag;
- };
- int main( )
- {
- Complex c1(3,4),c2(5,-10),c3; //调用构造函数创建3个对象
- double d;
- d=2.5+c1;//要求将一个double数据与Complex类数据相加
- cout<<d<<endl;
- return 0;
- }
- #include <iostream>
- using namespace std;
- class Complex
- {
- public:
- Complex( ){real=0;imag=0;} //默认构造函数
- Complex(double r){real=r;imag=0;}//转换构造函数
- Complex(double r,double i){real=r;imag=i;}//实现初始化的构造函数
- friend Complex operator + (Complex c1,Complex c2); //重载运算符“+”的友元函数,非标准类型,都需要实现重载运算符后才能相加
- void display( );
- private:
- double real;
- double imag;
- };
- Complex operator + (Complex c1,Complex c2)//定义运算符“+”重载函数
- {
- return Complex(c1.real+c2.real, c1.imag+c2.imag);
- }
- void Complex::display( )
- {
- cout<<"("<<real<<","<<imag<<"i)"<<endl;
- }
- int main( )
- {
- Complex c1(3,4),c2(5,-10),c3;
- c3=c1+2.5; //复数与double数据相加
- c3.display( );
- return 0;
- }