现在的位置: 首页 > 综合 > 正文

C/C++开发语言系列之15—C++类型转换函数

2013年12月06日 ⁄ 综合 ⁄ 共 6359字 ⁄ 字号 评论关闭

用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。

C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:
operator double( )
{
   return real;
}
类型转换函数的一般形式为

operator 类型名( )

{

   实现转换的语句

}

在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。
从函数形式可以看到,它与运算符重载函数相似,都是用关键字operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的double型数据,而且还会把Complex类对象作为double型数据处理。

那么程序中的Complex类对具有双重身份,既是Complex类对象,又可作为double类型数据。Complex类对象只有在需要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:
当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。

例1 使用类型转换函数的简单例子。
#include <iostream>
using namespace std;
class Complex
{
   public:

   Complex( ){

   cout<<"Complex(
)
"<<endl;

   real=0;

   imag=0;

    }

   Complex(double r,double i){

 
 cout<<"
Complex(double
r,double i)
"<<endl;

  real=r;

  imag=i;

   }

   operator double( ) {

 
     cout<<"
operator
double( )
"<<endl;

       return real;

   } //类型转换函数

   private:
   double real;
   double imag;
};

int main( )
{
   Complex c1(1,2),c2(3,-1),c3;

   double d;

 
 //
根据上下文,系统自动将一个double类型的数据与Complex类的对象相加

   d=12.5+c1;                 //或者 
 d=c1+12.5;    

   cout<<d<<endl;
   return 0;
}

程序结果:

Complex(double r,double i)      // 定义变量C1
Complex(double r,double i)     // 定义变量C2
Complex( )        // 定义变量C1
operator double( )       //d=12.5+c1; 根据上下文自动调用函数operator
double

13.5

完整的函数名称

Complex::operator double()     //注意中间有个空格

对程序的分析:

  1. 如果在Complex类中没有定义类型转换函数operator double,程序编译将出错。
  2. 如果在main函数中加一个语句:
       c3=c2;
    由于赋值号两侧都是同一类的数据,是可以合法进行赋值的,没有必要把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类对象(系统调用自动构造函数Complex(double r,double i)创建一个临时变量),由于它不能赋值给double型变量,而又有对double的重载函数,于是调用此函数,把临时类对象转换为double数据,然后赋给d。


例2:

#include <iostream>
using namespace std;
class Complex
{
   public:
   Complex( ){
cout<<"Complex( )"<<endl;
real=0;
imag=0;
    }
   Complex(double r,double i){
cout<<"Complex(double r,double i)"<<endl;
real=r;
imag=i;
   }
    //类型转换函数
   operator double( ) {
cout<<"operator double( )"<<endl;
return real;
   }

   private:
   double real;
   double imag;
};

int main( )
{
   Complex c1(1,2),c2(3,-1),c3;
   double d;
   //根据上下文,系统自动将一个double类型的数据与Complex类的对象相加
   d=12.5+c1;
   cout<<d<<endl;
  c1+c2;  //由于没有重载operator+运算符,所以会更加上下文调用两次operator double( ) 函数  d=c1+c2;也是调用2次


   return 0;
}

输出结果:


Complex(double r,double i)
Complex(double r,double i)
Complex( )
operator double( )
13.5
operator double( )
operator double( )

例2解析:c1+c2表达式导致系统根据上下文自动调用operator double( ) 函数两次,c1和c2分别调用函数operator
double( ) ,进行类别转换

例3:

稍微修改一下例2的代码:添加一个友元运算符函数

#include <iostream>
using namespace std;
class Complex
{
   public:
   Complex( ){
cout<<"Complex( )"<<endl;
real=0;
imag=0;
    }
   Complex(double r,double i){
cout<<"Complex(double r,double i)"<<endl;
real=r;
imag=i;
   }
    //类型转换函数
   operator double( ) {
cout<<"operator double( )"<<endl;
return real;
   }
   friend Complex operator + (Complex c1,Complex c2); //重载运算符“+”的友元函数

   private:
   double real;
   double imag;
};

//友元函数的方式实现对象的加法操作,所以return一个Complex 对象
Complex operator + (Complex c1,Complex c2)//定义运算符“+”重载函数
{

   cout<<"operator + (Complex c1,Complex c2)"<<endl;
   return Complex(c1.real+c2.real, c1.imag+c2.imag);
}

int main( )
{
   Complex c1(1,2),c2(3,-1),c3;
   double d;
   //根据上下文,系统自动将一个double类型的数据与Complex类的对象相加
   d=12.5+c1;
   cout<<d<<endl;
   d=c1+c2;
   return 0;
}

运行结果:

Complex(double r,double i)
Complex(double r,double i)
Complex( )
operator double( )
13.5
operator + (Complex c1,Complex c2)    //c1+c2 调用运算符重载函数
Complex(double r,double i)              // 调用return Complex(c1.real+c2.real, c1.imag+c2.imag); 
operator double( )    //d= 导致调用operator double( ) 函数

从前面的介绍可知: 对类型的重载和本文开头所介绍的对运算符的重载的概念和方法都是相似的。重载函数都使用关键字operator。因此,通常把类型转换函数也称为类型转换运算符函数,由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)。

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

例4 包含转换构造函数、运算符重载函数和类型转换函数的程序。
先阅读以下程序,在这个程序中只包含转换构造函数和运算符重载函数。
#include <iostream>
using namespace std;
class Complex
{
   public:
   //默认构造函数
   Complex( ){
  cout<<"Complex( )"<<endl;
  real=0;
  imag=0;
   }  
   //转换构造函数
   Complex(double r){
  cout<<"Complex(double r)"<<endl;
  real=r;
  imag=0;
   }
   

   //实现初始化的构造函数
   Complex(double r,double i){
  cout<<" Complex(double r,double i)"<<endl;
  real=r;
  imag=i;
   }
    //重载运算符“+”的友元函数
   friend Complex operator + (Complex c1,Complex c2); 
   void display( );
   private:
   double real;
   double imag;
};
//定义运算符“+”重载函数
Complex operator + (Complex c1,Complex c2)
{
   cout<<"operator + (Complex c1,Complex c2)"<<endl;
   return Complex(c1.real+c2.real, c1.imag+c2.imag);//调用Complex(double r,double i)函数创建一个对象
}
void Complex::display( )
{
   cout<<"("<<real<<","<<imag<<"i)"<<endl;
}

int main( )
{
   Complex c1(3,4),c2(5,-10),c3;
   cout<<endl<<endl;
   c3=c1+2.5; //复数与double数据相加
   c3.display( );
   return 0;

}

程序运行结果:

 Complex(double r,double i)
 Complex(double r,double i)
Complex( )

Complex(double r) //将2.5调用转换构造函数转为对象
operator + (Complex c1,Complex c2)//调用operator +完成运算操作
 Complex(double r,double i)  //函数中operator + 的最后一行代码调用的构造函数
(5.5,4i)

对程序的分析:

  1. 如果没有定义转换构造函数,则此程序编译出错。
       如  c3=1.1; 这直接调用转换构造函数Complex(double r)

  1. 现在,在类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)
  2. 如果把“c3=c1+2.5;”改为c3=2.5+c1; 程序可以通过编译和正常运行。过程与前相同。

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

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

    由于这个原因,一般情况下将双目运算符函数重载为友元函数。单目运算符则多重载为成员函数。
  3. 如果一定要将运算符函数重载为成员函数,而第一个操作数又不是类对象时,只有一个办法能够解决,再重载一个运算符“+”函数,其第一个参数为double型。当然此函数只能是友元函数,函数原型为

       friend operator+(double,Complex &);

    显然这样做不太方便,还是将双目运算符函数重载为友元函数方便些。
  4. 在上面程序的基础上增加类型转换函数:
       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( );
    其余部分不变。程序在编译时出错,原因是出现二义性。


   /*  产生二义性,编译器可以理解为

  1. c1.Complex::operator double( ) + 2.5
  2. operator+(c1,Complex(2.5))

   */

编译器的提示:
In function ‘int main()’:
error: ambiguous overload for ‘operator+’ in ‘c1 + 2.5e+0’           此行代码导致产生了二义性
note: candidates are:operator+(double, double)<built-in>    编译器内置的功能 + 运算,两个都是double
note:                 Complex operator+(Complex, Complex)       自定义的加法 运算,两个都是Complex类型

抱歉!评论已关闭.