【c/c++】类型转换函数(类型转换运算符重载函数)

转换构造函数能够将一个指定类型的数据转换为类的对象。可是不能反过来将一个类的对象转换为一个其余类型的数据(例如将一个Complex类对象转换成double类型数据)。在C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的做用是将一个类的对象转换成另外一类型的数据。ios

若是已声明了一个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类对象只有在须要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当须要的时候,编译系统会自动调用这些函数,创建一个无名的临时对象(或临时变量)。spa

必定要注意这里是只有在须要的时候,只有在须要的时候才会去调用。code


使用类型转换函数的简单例子。对象

#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;
   double d;
   d=2.5+c1;//要求将一个double数据与Complex类数据相加
   cout<<d<<endl;
   return 0;
}
输出结果:

5.5原型

对程序的分析:

1) 若是在Complex类中没有定义类型转换函数operator double,程序编译将出错。io

由于不能实现double 型数据与Complex类对象的相加。如今,已定义了成员函数 operator double,就能够利用它将Complex类对象转换为double型数据。请注意,程序中没必要显式地调用类型转换函数,它是自动被调用的,即隐式调用。编译

在什么状况下调用类型转换函数呢?编译系统在处理表达式 2.5 +cl 时,发现运算符“+”的左侧是double型数据,而右侧是Complex类对象,又无运算符“+”重载函数,不能直接相加,编译系统发现有对double的重载函数,所以调用这个函数,返回一个double型数据,而后与2.5相加。function


2) 若是在main函数中加一个语句:
    c3=c2;
请问此时编译系统是把c2按Complex类对象处理呢,仍是按double型数据处理? 因为赋值号两侧都是同一类的数据,是能够合法进行赋值的,没有必要把c2转换为double型数据。

3) 若是在Complex类中声明了重载运算符“+”函数做为友元函数:
    Complex operator+ (Complex c1,Complex c2)//定义运算符“+”重载函数
    {
        return Complex(c1.real+c2.real, c1.imag+c2.imag);
    }
若在main函数中有语句
    c3=c1+c2;
因为已对运算符“+”重载,使之能用于两个Complex类对象的相加,所以将c1和c2按Complex类对象处理,相加后赋值给同类对象c3。若是改成
    d=c1+c2; //d为double型变量
将c1与c2两个类对象相加,获得一个临时的Complex类对象,因为它不能赋值给double型变量,而又有对double的重载函数,因而调用此函数,把临时类对象转换为double数据,而后赋给d。

从前面的介绍可知,对类型的重载和对运算符的重载的概念和方法都是类似的,重载函数都使用关键字operator。所以,一般把类型转换函数也称为类型转换运算符函数,因为它也是重载函数,所以也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)。

假如程序中须要对一个Complex类对象和一个double型变量进行+,-,*,/等算术运算,以及关系运算和逻辑运算,若是不用类型转换函数,就要对多种运算符进行重载,以便能进行各类运算。这样,是十分麻烦的,工做量较大,程序显得冗长。若是用类型转换函数对double进行重载(使Complex类对象转换为double型数据),就没必要对各类运算符进行重载,由于Complex类对象能够被自动地转换为double型数据,而标准类型的数据的运算,是可使用系统提供的各类运算符的。

包含转换构造函数、运算符重载函数和类型转换函数的程序。class

先阅读如下程序,在这个程序中只包含转换构造函数和运算符重载函数。

#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;
}

输出的结果为:

(5.5,4i)


对程序的分析:
1) 若是没有定义转换构造函数,则此程序编译出错。

2) 如今,在类Complex中定义了转换构造函数,并具体规定了怎样构成一个复数。因为已重载了算符“+”,在处理表达式c1+2.5时,编译系统把它解释为
    operator+(c1, 2.5)
因为2.5不是Complex类对象,系统先调用转换构造函数Complex(2.5),创建一个临时的Complex类对象,其值为(2.5+0i)。上面的函数调用至关于
    operator+(c1, Complex(2.5))
将c1与(2.5+0i) 相加,赋给c3。运行结果为
    (5.5+4i)
3) 若是把“c3=c1+2.5;”改成c3=2.5+c1; 程序能够经过编译和正常运行。过程与前相同。

从中获得一个重要结论,在已定义了相应的转换构造函数状况下,将运算符“+”函数重载为友元函数,在进行两个复数相加时,能够用交换律。

若是运算符函数重载为成员函数,它的第一个参数必须是本类的对象。当第一个操做数不是类对象时,不能将运算符函数重载为成员函数。若是将运算符“+”函数重载为类的成员函数,交换律不适用。

因为这个缘由,通常状况下将双目运算符函数重载为友元函数。单目运算符则多重载为成员函数。

这个和咱们以前学过的所谓实参和传参的类型必须一致是一个道理,只不过这里就是更加的明确了,仔细了而已


4) 若是必定要将运算符函数重载为成员函数,而第一个操做数又不是类对象时,只有一个办法可以解决,再重载一个运算符“+”函数,其第一个参数为double型。固然此函数只能是友元函数,函数原型为
    friend operator+(double, Complex &);
显然这样作不太方便,仍是将双目运算符函数重载为友元函数方便些。

5) 在上面程序的基础上增长类型转换函数:
    operator double( ){return real;}
此时Complex类的公用部分为:
   public:
   Complex( ){real=0;imag=0;}
   Complex(double r){real=r;imag=0;}  //转换构造函数
   Complex(double r,double i){real=r;imag=i;}
   operator double( ){return real;}//类型转换函数
   friend Complex operator+ (Complex c1,Complex c2); //重载运算符“+”
   void display( );

其他部分不变。程序在编译时出错,缘由是出现二义性。

当类中出现了转换构造函数和类型转换函数的时候,必需要注意是否会出现二义性的问题