重载,类型转换和运算符

重载,类型转换和运算符

类类型转换:(class type conversions)
1 转换构造函数(conversion constructor):将实参类型转换为类类型
2 类型转换运算符(conversion operator):将类类型转化为其它类型

类型转换运算符

类型转换运算符:一种特殊的成员函数,一般形式如下:
operator type() const;
1) type表示任意类型(除了void类型),只要该类型能作为函数的返回类型;所以不允许转换为数组或者函数类型,但可以转化为指针类型或引用类型。
2) 没有显示的返回类型,形参列表必须为空,且必须定义成成员函数,且一般是const成员。

ex:

class SmallInt {
public:
    SmallInt(int = 0) {}    //conversion ctor
    operator int() const { return val; }    //conversion operator
private:
    int val;
};

3) 专家经验:
a 明智的使用类型转换运算符能极大的简化类的设计工作,使得类的使用更加容易。然而如果类类型和转换类型不存在明显的映射关系时,不定义也许会更好,否则会具有误导性。
b 作为代替手段,类可以定义一个或多个普通成员函数以从哥哥不同形式提取信息。

4)类型转换可能产生意外的结果
在实践中,类很少提供类型转运算符。然而,存在一种例外情况,对于类,定义向bool的类型转换还是比较普遍的。
ex:
对于if (cin >> i),标准输入定义了一个向bool转换的运算符。

然而有些情况下也可能引起惊讶:cin << i; 如果bool的类型转换不是显示的,那么该代码将通过编译。

首先把cin转化为bool,然后再提升为int,并作用于移位运算符,那么提升后的bool值将被左移i位;
这显然不科学。

为了防止这样的异常情况发生,C++11引入了显示的类型转换运算符(explicit operator):

class SmallInt {
public:
    explicit operator int() const {return val;}
};

a 和显示构造函数一样,编译器通常不会将一个显示的类型转换用于隐式类型转换。

SmallInt s = 3;
si + 3; //error 

b 当类型转换是显示时,我们也能执行类型转换,但必须显示的用强制类型转换。
static_cast<int>(si) + 3; //right

c 该规则存在一个例外,如果表达式被用作条件,则编译器会将显示类型转换自动应用于它。即,在用于条件时,显示转换会被隐式执行。
(但是笔者的xcode中仍然不能被隐式执行)

d 向bool的类型转换通常用于条件部分,因此operator bool一般定义为explicit

避免有二义性的类型转换

各种二义性。(看到这里,才知道C++真心麻烦,没有扎实的基本功,还真不容易发现这些问题。)

两个类提供相同的类型转换

class Y;
class X {   //X定义了接受B对象的转换构造
public:
    X() = default;
    X(const Y&) {}
};

class Y {    //Y定义了向X转换的类型转换运算符
public:
    operator X() const { return X(); }
};

//有如下函数,接受一个X对象
X f(const X&) {return X();}

//用Y对象调用---产生二义性
Y obj;
X x = f(obj);    //error

//此时必须显示调用
X x1 = f(obj.operator X());
X x2 = f(X(obj));

定义了多个类型转换规则

struct Z {
    //两个转换源都是算数类型
    Z(int = 0) {}
    Z(double) {}

    //两个转换对象都是算数类型
    operator int() const {return int();}
    operator double() const {return double();}
};

void f2(long double) {}

Z z1;
f2(z);    //error 不知道调用哪个类型转换运算符

long lg;
Z z2(lg);   //error 不知道调用哪个构造函数

专家经验:
1 不要令两个类执行相同的类型转换
2 避免转换目标都是内置算数类型的类型转换
In a word,除了显示的向bool转换之外,我们因该尽量避免定义类型转换函数,并且尽可能限制那些“显然正确”的非显示构造函数。

重载函数与转换构造

struct B {
    B(int ) {}
};

struct C {
    C(int) {}
};

void f3(const B& ) {}
void f3(const C& ) {}

f3(3);        //error,必须显示转换
f3(B(3));
f3(C(3));

函数匹配与重载运算符

当我们通过类类型对象进行函数调用时,只考虑该类型的成员函数。
而在表达式中使用重载的运算符时,无法判断正在使用的是成员函数还是非成员函数。因此,两者都应该在考虑范围之内。

class SmallInt {
    friend SmallInt operator+(const SmallInt&, const SmallInt& );
public:
    SmallInt(int = 0) {}
    operator int() const { return val; }
private:
    int val;
};

SmallInt operator+(const SmallInt&, const SmallInt& ) {
    return SmallInt();
}

SmallInt s1, s2;
s1 = s1 + s2;
int i = s1 + 3;   //error. 或者把s1转换为int,调用内置版本+;或者把3转换为类类型,调用+重载版本
int i = s1.operator int() + 3;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值