码迷,mamicode.com
首页 > 其他好文 > 详细

重载操作符与转换(下)

时间:2016-02-28 13:51:37      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:

  • 转换与类类型

可用一个实参调用的非 explicit 构造函数定义一个隐式转换。当提供了实参类型的对象而需要一个类类型的对象时,编译器将使用该转换。这种构造函数定义了到类类型的转换。除了定义到类类型的转换之外,我们还可以定义从类类型的转换。即,我们可以定义转换操作符,给定类类型的对象,该操作符将产生其他类型的对象。像其他转换一样,编译器将自动应用这个转换。在介绍如何定义这种转换之前,将说明它们为什么可能有用。

假定想要定义一个名为 SmallInt 的类,该类实现安全小整数,这个类将使我们能够定义对象以保存与 8 位 unsigned char 同样范围的值,即,0 到 255。这个类可以捕获下溢和上溢错误,因此使用起来比内置 unsigned char 更安全。我们希望这个类定义 unsigned char 支持的所有操作。具体而言,我们想定义 5 个算术操作符(+-*/%)及其对应的复合赋值操作符,4 个关系操作符(<<=>>=),以及相等操作符(==!=)。显然,需要定义 16 个操作符。而且,我们希望可以在混合模式表达式中使用这些操作符。例如,应该可以将两个 SmallInt 对象相加,也可以将任意算术类型加到 SmallInt。通过为每个操作符定义三个实例来达到目标:

int operator+(int, const SmallInt&);
     int operator+(const SmallInt&, int);
     SmallInt operator+(const SmallInt&, const SmallInt&);

因为存在从任意算术类型到 int 的转换,这三个函数可以涵盖支持 SmallInt 对象的混合模式使用的要求。但是,这个设计仅仅接近内置整数运算的行为,它不能适当处理浮点类型混合模式操作,也不能适当支持 longunsigned intunsigned long 的加运算。问题在于这个设计将所有算术类型(甚至包括那些比 int 大的)转换为 int 并进行 int 加运算。即使忽略浮点或大整型操作数的问题,如果要实现这个设计,也必须定义 48 个操作符!幸好,C++ 提供了一种机制,利用这种机制,一个类可以定义自己的转换,应用于其类类型对象。对 SmallInt 而言,可以定义一个从 SmallIntint 类型的转换。如果定义了该转换,则无须再定义任何算术、关系或相等操作符。给定到 int 的转换,SmallInt 对象可以用在任何可用 int 值的地方。//弊端:必须对加减乘除等所有操作符进行重载;必须对与整型、浮点型、double型等所有类型的操作都进行重载。

如果存在一个到 int 的转换,则以下代码:

SmallInt si(3);
     si + 3.14159;         // convert si to int, then convert to double

可这样确定:

si 转换为 int 值。将所得 int 结果转换为 double 值并与双精度字面值常量 3.14159 相加,得到 double 值。

  • 转换操作符

转换操作符是一种特殊的类成员函数。它定义将类类型值转变为其他类型值的转换。转换操作符在类定义体内声明,在保留字 operator 之后跟着转换的目标类型:

class SmallInt {
     public:
         SmallInt(int i = 0): val(i)
         { if (i < 0 || i > 255)
            throw std::out_of_range("Bad SmallInt initializer");
         }
         operator int() const { return val; }
     private:
         std::size_t val;
     };

转换函数采用如下通用形式:

operator type();

这里,type 表示内置类型名、类类型名或由类型别名定义的名字。对任何可作为函数返回类型的类型(除了 void 之外)都可以定义转换函数。一般而言,不允许转换为数组或函数类型,转换为指针类型(数据和函数指针)以及引用类型是可以的。转换函数必须是成员函数,不能指定返回类型,并且形参表必须为空

虽然转换函数不能指定返回类型,但是每个转换函数必须显式返回一个指定类型的值。例如,operator int 返回一个 int 值;如果定义 operator Sales_item,它将返回一个 Sales_item 对象,诸如此类。转换函数一般不应该改变被转换的对象。因此,转换操作符通常应定义为 const 成员

  • 使用类类型转换

只要存在转换,编译器将在可以使用内置转换的地方自动调用它:

在表达式中:

SmallInt si;
     double dval;
     si >= dval          // si converted to int and then convert to double

在条件中:

if (si)                // si converted to int and then convert to bool

将实参传给函数或从函数返回值:

int calc(int);
     SmallInt si;
     int i = calc(si);      // convert si to int and call calc

作为重载操作符的操作数:

// convert si to int then call opeator<< on the int value
     cout << si << endl;

在显式类型转换中:

int ival;
     SmallInt si = 3.541; //
     instruct compiler to cast si to int
     ival = static_cast<int>(si) + 3;

使用转换函数时,被转换的类型不必与所需要的类型完全匹配。必要时可在类类型转换之后跟上标准转换以获得想要的类型。例如,在一个 SmallInt 对象与一个 double 值的比较中:

SmallInt si;
     double dval;
     si >= dval // si converted to int and then convert to double
  • 只能应用一个类类型转换

类类型转换之后不能再跟另一个类类型转换。如果需要多个类类型转换,则代码将出错。例如,假定有另一个类 Integral,它可以转换为 SmallInt 但不能转换为 int

// class to hold unsigned integral values
     class Integral {
     public:
         Integral(int i = 0): val(i) { }
         operator SmallInt() const { return val % 256; }//不能再转换为int了
     private:
         std::size_t val;
     };

可以在需要 SmallInt 的地方使用 Integral,但不能在需要 int 的地方使用 Integeral

int calc(int);
     Integral intVal;
     SmallInt si(intVal);  // ok: convert intVal to SmallInt and copy to si
     int i = calc(si);     // ok: convert si to int and call calc
     int j = calc(intVal); // error: no conversion to int from Integral

 

 

重载操作符与转换(下)

标签:

原文地址:http://www.cnblogs.com/predator-wang/p/5224581.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!