C++ Primer 学习笔记:类型转换

一、隐式转换

1.算术转换

1)条件表达式中,非布尔类型变量转化为布尔类型。0值转换为false,非0值转换为true。

2)赋值语句中,右值类型转换为左值类型。

举个例子:

bool b = 42;
int i=b;
第一句语句中,42转换成true,第二句语句中,b的值true转换成1,赋给i。

3)算数表达式中的类型转换分为以下几步:

①  整型提升

凡是类型中所有的值可以全部存入int类型的变量(如bool,char,signed char,unsigned char,short,unsigned short……),转换为int。

对于类型中所有的值无法全部存入int类型的变量(如wchar_t,char16_t,char32_t……),转换为可以包含它所有值的最小的类型,如int,unsigned int,long,unsigned long,long long,unsigned long long等。

②  有、无符号的情况

先进行整型提升。

在整型提升之后:

若符号相同,则将小类型转换为大类型。

若无符号类型大于有符号类型,则将有符号类型转换为无符号类型。

若有符号类型大于无符号类型,则分两种情况:

无符号类型中的所有值都可以存到有符号类型中:将无符号类型转换为有符号类型。

否则,将有符号类型转换为无符号类型。

举个例子:

long + unsigned int

如果sizeof(int) == sizeof(long),此时无符号类型unsigned int中的所有值无法全部存到long中,所以将long转换为unsigned int。

如果sizeof(int) < sizeof(long),则就将unsigned int 转换为long。

由于无符号数恒大于等于0,将有符号数转换为无符号数会导致错误。

2. 数组名转换为指针

数组名会被隐式地转换为指向数组首元素的指针。

3. 指针转换

1)指针转换为布尔类型

char *cp = get_string();
if (cp)......
2)指向非const 类型数据的指针转换为指向const类型的指针

int i;
const int *p = &i;

二、显式转换

C++中提供4种显式类型转换方式。

1. static_cast

常用的转换方式,使用举例如下:

double slope = static_cast<double>(j)/i;

2. dynamic_cast

将基类的指针或引用安全地转换到派生类的指针或引用。

如果转换失败,指针转换时返回0,引用转换时抛出bad_cast异常。

使用举例:

if (Derived dp = dynamic_cast<Derived>(bp)){......}
else {......}
3. const_cast

具有去常量性的作用,可以将指向const类型的指针转换为指向非const类型的指针,举例如下:

const char *pc;
char *p = const_cast<char*>(pc);
4. reinterpret_cast

一种重编译的类型转换,使用较少。

三、类类型转换

1. 转换运算符

类类型转换运算符格式如下:

operator type() const;
无返回类型,无参数,声明为类的const成员函数。

可以通过加上explicit关键字来防止自动的类型转换。举例如下

class Smalllnt{
public:
    explicit operator int() const{
        return val;
}
}
此时,类似si + 3 的表达式是错误的,编译器不会自动把si转换成int类型。必须显式转换:static_cast<int>(si) + 3。

2. 二义性

在类类型转换中,可能会出现一些二义性。

1)构造函数与转换运算符的二义性

比如以下语句:

class A: A(const B&);
class B:operator A() const;
A f(const A&);
B b;
A a = f(b);
此时,编译器不知是将B 类型的b 调用类型转换运算符转换为A,还是调用A的构造函数。正确的做法是显式写出,写法如下:

A a1 = f(b.operator A());
A a2 = f(A(b));

2) 涉及算术类型的二义性

在两个转换源或转换目标均为算术类型时,很容易出现二义性。比如以下语句中:

class A{
      A(int = 0);
      A(double);
      operator int() const;
      operator double() const;
}
void f2(long double);
A a;
f2(a);
long lg;
A a2(lg);
在f2(a)中,编译器不知是将a转换为int还是double类型。

在A a2(lg)中,编译器也不知是将lg转换成int还是double类型。

可见,我们要避免两个转换源或转换目标均为算术类型的情况。

3) 重载函数二义性

在重载函数中,也容易产生二义性

class C { C(int);}
class E { E(double);}
void manip2(const C&);
void manip2(const D&);
manip2(10);

在manip2(10)中,编译器也不知是将10转换成C还是D,产生了二义性。

4) 运算符重载与类类型转换的冲突

重载的运算符容易与类类型转换产生冲突

class Smalllnt{
    friend Smalllnt operator+(const Smalllnt&,const Smalllnt&){...}
    public:
        Smalllnt(int = 0);
        operator int() const{return val;}
    private:
        size_t val;
}
Smalllnt s1,s2;
Smalllnt s3 = s1 + s2;
int i = s3 + 0;
在 int i = s3 + 0; 中,编译器也不知是将0转换为Smalllnt类型,然后调用重载的+运算符,还是将s3转换成int类型,导致了冲突。







   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值