zoukankan      html  css  js  c++  java
  • 15.9 用户定义的转换

     1 class SmallInt{
     2 friend operator+(const SmallInt&,int);
     3 friend operator-(const SmallInt&,int);
     4 friend operator+(int,const SmallInt&);
     5 friend operator-(int,const SmallInt&);
     6 public:
     7 Samll(int ival):value(ival){};
     8 operator+(const SmallInt&);
     9 operator-(const SmallInt&);
    10 //...
    11 private:
    12 int value;
    13 }

    定义6个操作,实现了SmallInt类与int型的运算,如:
    SamllInt si(3);
    si+3.14159
    首先3.14159被转换成整型值3
    调用operator+(const Small&,int),返回6,
    但这并不是我们想要的结果,我们想得到6.174159

    15.9.1 转换函数

    C++提供一种机制,每个类可以定义一组“可被应用到该类型对象上的转换”,对于SmallInt队形,这里定义了该对象到int型的转换

    1 class SmallInt{
    2 public:
    3 SamllInt(int val):value(ival){}
    4 //转换操作符
    5 operator int(){return value;}
    6 private:
    7 int value;
    8 }

    SmallInt没有提供操作符重载
    int()是一个转换函数,它定义了一个用户定义的转换
    SmallInt si(3);
    si+3.14159
    则,调用SmallInt的转换函数,产生整形值3
    整型值3被转换成3.0,得到6.14159
    这样,所有int型能够执行的操作,si都能执行,如:si>127,将调用转换操作函数转成int

    修改后的SmallInt

     1 class SmallInt{
     2 friend istream& operator>>(istream & is,SmallInt& s);
     3 friend ostream& operator<<(osstrea & os,const SmallInt &s)
     4 {return os<<s.value;}
     5 public:
     6 SmallInt(int i=0):value(rangeCheck(i)){}
     7 int operator=(int i){return (value=rangeCheck(i));}
     8 operator int(){return value;}
     9 private:
    10 int rangeCheck(int);
    11 int value;
    12 }
     1 istream& operator>>(istream &is,SmallInt &si)
     2 {
     3 int ix;
     4 is>>ix;
     5 si=ix; //调用SmallInt::operator=(int)
     6 return is;
     7 }
     8 
     9 int SmallInt::rangeCheck(int i)
    10 {
    11 //...
    12 }

    转换函数不仅可以转换成内置类型,也可以是其他类型,如:

     1 #inlcue "SmallInt.h”
     2 typedef char* tName;
     3 class Token{
     4 public:
     5 Token(char*,int);
     6 operator SmallInt(){return val;}
     7 operator tName(){reurn name;}
     8 operator int(){return val;}
     9 private:
    10 SmallInt val;
    11 char* name;
    12 }
    13 
    14 Token t("aa",127);
    15 int a=t;

    这里调用Token::operator int()函数返回一个SmallInt对象,然后调用SmallInt::operator int()函数返回一个int型对象,所以Token的int转换函数直接返回SmallInt对象

    转换函数标准格式:
    (1) 转换函数必须是成员函数
    (2) 以operator开头
    (3) 声明不能指定返回类型和参数表

    强制转换会调用转换函数,如:

     1 #include "Token.h"
     2 Token tok("fun",78);
     3 //调用Token::operator SmallInt()
     4 SmallInt tokval=SmllInt(tok);
     5 //或者,执行隐式转换
     6 SmallInt tokval2=tok;
     7 //调用Token::operator tName()
     8 char * tokName =static_cast<char*>(tok);
     9 //或者,执行隐式转换
    10 char* tokName2=tok;


    Token::operator tName()转换函数提供了访问类私有成员的可能性,这样是我们不希望的,如:
    *tokName='P';//这样我们修改了类的私有成员
    我们可以重新定义tName

    1 typedef const char* tName;
    2 char *p=tok;//error,不允许把char*转换成const char*
    3 const char *p2=tok//ok

    第二种方法是改用string型,如:

     1 class Token{
     2 public:
     3 Token(string ,int);
     4 operator SmallInt(){return val;}
     5 operator string(){return name;}
     6 operator int(){return val;}
     7 //...
     8 private:
     9 SmallInt val;
    10 string name;
    11 };

    采用以传值方式返回string,可以防止在类外修改私有成员的值,在执行构造函数的时候,name对象是重新获得的一块内存区域,对传进来的string也没有影响。


    使用转换函数时,转换的目标类型必须与转换函数的类型完全匹配吗?如:
    extern void calc(double);
    Token tok("aaa",44);
    calc(tok);//调用tok.operator int()函数,再执行int->double的标准转换


    当使用用户定义的转换之后,只能允许使用标转转换序列,如果多次使用用户定义的转换,将是非法的。如:
    extern void calc(int)
    Token tok("aa",37);
    calc(tok);//若没有定义Token::operator int(),则程序将报错
    因为,calc(tok)将首先调用Token::operator SmallInt()将对象转换成SmallInt对象,再调用SmallInt::operator int()将Small对象转换成int型,这样就两次调用了用户定义的转换,程序将报错。

    如果转换函数的类型与类类型之间没有逻辑匹配,则最好不要定义转换函数,如:

    1 class Date{
    2 public:
    3 operator int();
    4 private:
    5 int month,day,year;
    6 }

    当调用int()时,却不知到该返回哪个值。

    15.9.2 用构造函数作为转换函数
    构造函数提供了把一种类型转换成另外一种类型的方式,
    SmallInt的构造函数SmallInt(int) 提供了一种把int型转成SmallInt型的方法。如:

    1 extern void calc(SmallInt);
    2 int i;
    3 calc(i);//编译器调用SmallInt(int)把i转成SmallInt对象
    4 可以采用如下理解:
    5 {
    6 SmallInt temp=SmallInt(i);
    7 calc(temp);
    8 }

    构造函数的参数也可以是另外一种类型,如:

    class Number{
    public:
    Number(const SmallInt&);
    }
    extern void func(Number);
    SmallInt si(8);
    func(si);//将调用Num

    构造函数执行隐式转换是,构造函数的参数类型必须与被转换的值的类型完全匹配么?
    extern void calc(SmallInt);
    double dobj;
    calc(dobj);//先执行标准转换,double->int,在构造函数int->SmallInt


    我们可以在构造函数加explicit关键字来取消隐式转换,如:

    class Number{
    public:
    explicit Number(const SmallInt &);
    };
    
    extern void func(Number);
    SmallInt si(87);
    int main()
    {
    func(si); //从SmallInt对象到Number对象没有隐式转换
    }

    不过我们可以:
    func(Number(si)); //显示调用构造函数
    func(static_cast<Number>(si));//强制转换

  • 相关阅读:
    xps转换为pdf工具
    公差与配合教案 2
    C#与C++抉择【z】
    MATLAB C#混合编程demo
    数据结构 第6章 图
    科技英语翻译480句 (九) 举例、异同、例外
    理论与数学应用互助交流QQ群(6314910) 简介【谢绝转载】
    数据结构 第3章 栈和队列
    精通Matlab与C/C++混合程序设计(第2版)
    科技英语翻译480句 (三) 原因、结果
  • 原文地址:https://www.cnblogs.com/estival/p/3242474.html
Copyright © 2011-2022 走看看