C++类型转换分为:隐式类型转换和显式类型转换

一、隐式类型转换

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

int ival = ;
double dval = 3.14159; ival + dval;//ival被提升为double类型

2)一种类型表达式赋值给另一种类型的对象:目标类型是被赋值对象的类型

int *pi = ; // 0被转化为int *类型
ival = dval; // double->int

例外:void指针赋值给其他指定类型指针时,不存在类型转换,编译出错,编译器根据指针类型来确定对象的所占空间大小,从而来操作对象

3)将一个表达式作为实参传递给函数调用,此时形参和实参类型不一致:目标转换类型为形参的类型

extern double sqrt(double);

cout << "The square root of 2 is " << sqrt() << endl;
//2被提升为double类型:2.0

4)从一个函数返回一个表达式,表达式类型与返回类型不一致:目标转换类型为函数的返回类型

double difference(int ival1, int ival2)
{
return ival1 - ival2;
//返回值被提升为double类型
}

二、显式类型转换
C     风格: (type-id)
C++风格: static_castdynamic_castreinterpret_cast、和const_cast..

static_cast:

用法:static_cast < type-id > ( expression )

说明:该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。

它主要有如下几种用法:

  • 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把void指针转换成目标类型的指针(不安全!!)
  • 把任何类型的表达式转换成void类型。

dynamic_cast:

用法:dynamic_cast < type-id > ( expression )

说明:该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

什么时候需要dynamic_cast强制转换:简单的说,当无法使用virtual函数的时候,此时可以用dynamic_cast实现多态

Wicrosoft公司提供给我们一个类库,其中提供一个类Employee.以头文件Eemployee.h和类库.lib分发给用户,显然我们并无法得到类的实现的源代码

//Emplyee.h
class Employee
{
public:
virtual int salary();
}; class Manager : public Employee
{
public:
int salary();
}; class Programmer : public Employee
{
public:
int salary();
};

我们公司在开发的时候建立有如下类:

class MyCompany
{
public:
void payroll(Employee *pe);
//
}; void MyCompany::payroll(Employee *pe)
{
//do something
}

但是开发到后期,我们希望能增加一个bonus()的成员函数到W$公司提供的类层次中。假设我们知道源代码的情况下,很简单,增加虚函数:

//Emplyee.h
class Employee
{
public:
virtual int salary();
virtual int bonus();
}; class Manager : public Employee
{
public:
int salary();
}; class Programmer : public Employee
{
public:
int salary();
int bonus();
}; //Emplyee.cpp int Programmer::bonus()
{
//
}

payroll()通过多态来调用bonus()

class MyCompany
{
public:
void payroll(Employee *pe);
//
}; void MyCompany::payroll(Employee *pe)
{
//do something
//pe->bonus();
}

但是现在情况是,我们并不能修改源代码,怎么办?dynamic_cast华丽登场了!

在Employee.h中增加bonus()声明,在另一个地方定义此函数,修改调用函数payroll().重新编译,ok

//Emplyee.h
class Employee
{
public:
virtual int salary();
}; class Manager : public Employee
{
public:
int salary();
}; class Programmer : public Employee
{
public:
int salary();
int bonus();//直接在这里扩展
}; //somewhere.cpp int Programmer::bonus()
{
//define
}
class MyCompany
{
public:
void payroll(Employee *pe);
//
}; void MyCompany::payroll(Employee *pe)
{
Programmer *pm = dynamic_cast<Programmer *>(pe); //如果pe实际指向一个Programmer对象,dynamic_cast成功,并且开始指向Programmer对象起始处
if(pm)
{
//call Programmer::bonus()
}
//如果pe不是实际指向Programmer对象,dynamic_cast失败,并且pm = 0
else
{
//use Employee member functions
}
}

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

class Base
{
public:
int m_iNum;
virtual void foo();
}; class Derived:public Base
{
public:
char *m_szName[];
}; void func(Base *pb)
{
Derived *pd1 = static_cast<Derived *>(pb); Derived *pd2 = dynamic_cast<Derived *>(pb);
}

在上面的代码段中,
如果pb实际指向一个Derived类型的对象,pd1和pd2是一样的,并且对这两个指针执行Derived类型的任何操作都是安全的;
如果pb实际指向的是一个Base类型的对象,那么pd1将是一个指向该对象的指针,对它进行Derived类型的操作将是不安全的(如访问m_szName),而pd2将是一个空指针(即0,因为dynamic_cast失败)。

dynamic_cast会进行动态类型检查,若基类指针指向派生类对象,则可以转为派生类型指针,否则,转换失败,返回NULL,即当指针的动态类型与转换后的类型不一致时,编译出错

另外要注意:Base要有虚函数,否则会编译出错;static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。

最新文章

  1. 编辑word文档过程中输入法无法正常使用
  2. sqlite的ef使用小结
  3. [NOIP2011] 观光公交(贪心)
  4. GitHub Extension for Visual Studio 2.0 is now available
  5. 第十周java 学习总结
  6. shell 简介
  7. List应用举例
  8. 【零基础学习iOS开发】【02-C语言】10-函数
  9. node.js 安装express 提示 command is not found
  10. 解决“重新安装vmware-tools”灰色而无法安装的问题
  11. js修改伪类元素样式
  12. was unable to start within 45 seconds. If the server requires more time, try increasing the timeout
  13. 一文入门HTML5
  14. Java 中12个原子操作类
  15. 初识AutoMapper
  16. 使用SqlBulkCopy批量插入数据,测试20万条用时5秒
  17. c++ ado 程序终止时崩溃
  18. VS2013下.Net Framework4配置FineUI4.14
  19. python第十二课——for in循环
  20. JVM体系结构和工作方式

热门文章

  1. Android 计算view 的高度
  2. biff - 新到邮件提醒
  3. webgl推荐书籍
  4. 认识单文件组件.vue 文件
  5. 用 vue cli 脚手架搭建单页面 Vue 应用(进阶2)
  6. No-8.循环
  7. python 调用exe程序
  8. react-native Android WARNING: API &#39;variant.getMergeAssets()&#39; is obsolete and has been replaced with &#39;variant.getMergeAssetsProvider()&#39;.
  9. urlEncoder
  10. [Python3网络爬虫开发实战] 3.2.1-基本用法