C++的类型转换

在C++中,类型转换可分为"隐式类型转换" 和 "强制类型转换"。

隐式类型转换

      隐式转换会发生在以下几种情况中:

  • 将一种算术类型值赋给另一种算术类型变量;
  • 同一表达式包含不同的数据类型;
  • 传递参数给函数时;
  • 函数返回表达式的类型与函数返回值类型不一致时。
  • 初始化和赋值时进行的转换

      在编译器实现以下代码:

	char a = 'a';
	int b = a;
	cout << a << endl;
	cout << b << endl;

  运行结果:

    

  通过测试可以看出char类型的变量转换为int类型,而且我们并没有做特殊处理,结果完全由编译器自动完成。

       在此类型转换中是由char 转换为 int,是由取值范围小的转为取值范围大的,那反过来呢?

       执行下列代码:

	long long l = 123456789;
	float f = l;
	cout << l << endl;
	cout << f << endl;

      运行结果:

      由于float只有6位有效数字,所以它截取long long型值的前6位。因此当大范围转小范围会出现精度的丢失。

摘自《C++Primer Plus》潜在的类型数值转换问题:

转换

潜在问题

将较大浮点类型转换为较小的浮点类型

精度(有效数位)降低,值可能超出目标类型的取值范围,在这种情况下,结果将不确定

将浮点类型转换为整型

小数部分丢失,原来的值可能超出目标类型的取值范围,这种情况下,结果将不确定

将较大的整型转换为较小的整型

原来的值可能超出目标类型的取值范围,通常只复制右边的字节

 

   在C++11中给出了大括号初始化的方式,其对于类型转换要求较为严格。 

      如执行下述代码:

	float f = 1.234567;
	int a{ f };
	cout << f << endl;
	cout << a << endl;
	return 0;

      结果编译出错

      列表初始化不允许收缩转换。

 

  • 表达式中的转换

在表达式中的转换有两种情况:

1. 自某一类型变量出现就自动转换;

2. 混合类型的表达式,较小数据类型会转换为较大数据类型。

    上述自动转换发生情况:在C++中枚举类型,布尔型或有符号或无符号的字符、短整数、整数位域。如果一个int可以表示上述类型,则其将被自动转换为整型。这种转换也称为整型提升

     另外一种情况比较好理解:如果表达式有一个int型变量,一个double型变量,则在表达式计算时会将int型提升为double型。

  • 参数传递时转换

        执行下面代码:

int SquartRoot(double x)
{
	// 函数参数被提升至double
	return sqrt(x);
}

double Quadratic(int x){
	return x*x;
	// 返回值被提升至double类型
}

int main()
{
	int a = 100;
	int res_sqrt = SquartRoot(a);
	double res = Quadratic(a);

	return 0;
}

 

小结:

一种算数类型转换为另一种参数类型

目标类型是被赋值对象的类型

表达式转换

整型提升

在混合类型的算术表达式中, 最宽的数据类型成为目标转换类型。

将一个表达式作为实参传递给函数调用,形参与实参类型不一致

目标转换类型为形参的类型

从一个函数返回一个表达式,表达式类型与返回类型不一致

目标转换类型为函数的返回类型

 

强制类型转换

      首先我们比较熟悉的,C语言所提供的强制类型转换方式:

(TypeName) value; // TypeName是我们所期望的变量类型

      C++也提供类似的转换方式:

TypeName (value); //  其意义与C风格一样,这么做只是为了让强制类型转换像是函数调用一样

       除此之外就是C++专门提供的四个强制类型转换运算符: (重点)

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast

      作用:可以根据目的选择合适的运算符,而不是通用的类型转换。

  • static_cast

语法: static_cast <type_name> ( Expression )

说明

  • 仅当type_name可被隐式转换为Expression所属类型,或是Expression 可被隐式转换为type_name所属类型,其转换合法;
  • 该运算符把expression转换为type_name类型,但没有运行时类型检查来保证转换的安全性。

用法

  1.  用于基本数据类型间转换,由于无需进行数据转换,所以enum可以转换为int,double转换为int等等。(安全性需要开发人员来保证)
  2.  空指针转换为目标类型的空指针。(不安全
  3.  把任何类型的表达式转换为void型。
  4.  用于类层次结构中基类与派生类之间的转换:

             上行转换是安全的;

              下行转换时,由于没有动态类型检查,所以不是安全的。

注意: static_cast不能转换掉Expression的const、volitale属性。

  • dynamic_cast

语法: dynamic_cast <type_name> ( Expression )

说明

  • 该运算符把Expression 转换成type_name类型的对象。type_name必须是类的指针类的引用或者void *
  • type_name是类指针,那么Expression 也必须是一个指针。type_name是一个引用,那么Expression 也必须是一个引用。

用法

  1.  主要用于类层次间基类与派生类的转换,不同于static_cast的是其下行转换具有类型检测,比较安全。
  2.  用于类之间的交叉转换。
  • 下行转换:
class Base{
    /*
      要dynamic_cast进行转换一定要有虚函数,
      否则编译出错,而static_cast没有此限制
    */
	virtual void func()
	{}
public:
	int _data;
};

class Derived : public Base{
public:
	int _val;
};

int main()
{

	Base *pb = new Base;
	pb->_data = 10;
	Derived *pd1 = static_cast<Derived*>(pb);
	Derived *pd2 = dynamic_cast<Derived*>(pb);

	delete pb;
	return 0;
}

       通过运行:

       可以看出:pd1与pb指向一致,那么对pd1进行操作时,会对b对象产生影响,且访问派生类成员也会出错,所以是不安全的。而pd2成了空指针,就没有之前的安全问题。

  • 为什么一定要有虚函数?

        因为类型检查所需的运行时类型信息保存在虚函数表中,所以要有虚函数。

  • 交叉转换

       执行如下代码:

class Base{
	virtual void func()
	{}
public:
	int _data;
};

class Derived_A : public Base{

};

class Derived_B : public Base{

};

int main()
{

	Derived_A *pb = new Derived_A;
	pb->_data = 10;
	Derived_B *pd1 = static_cast<Derived_B*>(pb);
	Derived_B *pd2 = dynamic_cast<Derived_B*>(pb);

	delete pb;
	return 0;
}

        执行结果是:static_cast不允许交叉转换,dynamic_cast可以转换且结果为空指针。

  • const_cast

语法: const_cast <type_name> ( Expression )

作用

        当一个值大多数时候是常量,而有时需要进行修改时,可以通过此方式将常量属性修改。

说明

  • type_name与Expression 除了const和volatile特征可以不同以外,其他类型必须相同;
  • 常量指针被转换为非常量指针,并且仍然指向原来对象;
  • 常量引用被转换为非常量引用,并且仍然指向原来的对象;
  • 常量对象转换为非常量对象。
  • reinterpret_cast

语法: reinterpret_cast <type_name> ( Expression )   

说明

  • type_name必须时一个指针、引用、算术类型、函数指针、成员指针;
  • 它可以把指针转化为整数,也可以把一个整数转换为指针;
  • 它并不支持所有类型转换,如:不能将指针转换为更小值的整型或浮点型;不能将函数指针转换为数据指针;
  • 在把某一整数转换为原来类型的指针,还可以的到原先的指针值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值