zoukankan      html  css  js  c++  java
  • C++转换构造函数和隐式转换函数 ~ 转载

    原文地址: C++转换构造函数和隐式转换函数

    用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个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;
     #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;
     }

    对程序的分析:

    1) 如果在Complex类中没有定义类型转换函数operator double,程序编译将出错。因为不能实现double 型数据与Complex类对象的相加。现在,已定义了成员函数 operator double,就可以利用它将Complex类对象转换为double型数据。请注意,程序中不必显式地调用类型转换函数,它是自动被调用的,即隐式调用。在什么情况下调用类型转换函数呢?编译系统在处理表达式 2.5 +cl 时,发现运算符“+”的左侧是double型数据,而右侧是Complex类对象,又无运算符“+”重载函数,不能直接相加,编译系统发现有对double的重载函数,因此调用这个函数,返回一个double型数据,然后与2.5相加。

    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型数据,而标准类型的数据的运算,是可以使用系统提供的各种运算符的。

    [例10.10] 包含转换构造函数、运算符重载函数和类型转换函数的程序。先阅读以下程序,在这个程序中只包含转换构造函数和运算符重载函数。

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

    注意,在Visual C++ 6.0环境下运行时,需将第一行改为#include <iostream.h>,并删去第2行,否则编译不能通过。


    对程序的分析:
    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( );

    其余部分不变。程序在编译时出错,原因是出现二义性。

  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/sanghai/p/7624877.html
Copyright © 2011-2022 走看看