---恢复内容开始---

最近做笔试题经常会碰到有关类型转换的题型,所以结合例子做下总结,也是希望自己能更时刻的理解类型转换。

C++的类型转换包括内置类型和类类型对象的转换。

(1) 1.1隐式类型转换(implicit type conversion) :转换规则由编译器自动执行,无需程序员的介入,有时甚至不需要程序员了解。

例子:

int ival = 0;

ival = 3.14 + 3; //会有编译警告出现

其中3.14是double型字面值常量,而3是int型字面值常量,C++在执行算术运算前,会将两操作数转换为同一数据类型,而不是不同类型直接操作。C++定义的算术类型的内置转换原则是尽可能的防止精度损失。转换原则采取两数据元素精度值最高的为标准进行转换,在本例中算术计算得到的和为double型,赋值时再将double转换成int。

笔试题(某科技公司笔试题)

unsigned  int a=2003;

int count=0;

int b=-2;

while((b+a)>0)

{

a=a+b;

count++;

}

count = ? (while条件判断中,因为ab的类型不一致,在进行运算操作时会统一内置转换为无符号,条件的值永远大于零,而造成死循环)

1.2 何时发生隐式类型转换

1.2.1在混合类型的表达式中,其操作数被转换为相同的类型:

int ival;

double dval;

ival >= dval // ival被转换成double

1.2.2用作条件的表达式被转换成bool类型:

int ival;

if (ival) //ival转换成bool

while (cin) //cin转换成bool

1.2.3用一表达式初始化某个变量,或将一表达式赋值给某个变量,则该表达式被转换为该变量类型。

int ival = 3.14;//3.14转换成int

int *ip;

ip = 0;   //int 0被转换为int *的空指针

1.3 隐式转换的类型

1.3.1指针转换

在使用数组时,大多数情况下数组都会自动转换为指向第一个元素的指针。

int ia[10];

int *ip = ia; //ia被转换成指针

1.3.2  转换为bool类型

1.3.3算术类型与bool类型的转换

1.3.4转换与枚举类型

1.3.5转换为const对象

1.3.6由标准库类型定义的转换

string s;

while (cin>>s) //即读入cin,将istream类型转换为bool类型,检测流状态,读入成功则流的状态将导致上述类型转换为bool后获得true,否则为false.

 (2) 2.1显式类型转换(explicit type conversion) : c++的命名强制类型转换,包括static_cast、dynamic_cast、const_cast和reinterpret_cast;

而旧式强制类型转换:

1.C风格(C-style)强制转型如下:(Type) expression

2.函数风格(Function-style)强制转型使用这样的语法:Type(expression)

这两种形式之间没有本质上的不同,仅是括号位置的差别,这两种形式称为旧风格的强制转型,是c++为了“对标准C++之前编写的程序”保持向后兼容性及保持与C语言的兼容性。其有与c++的命名强制类型转换一样的行为,但旧式强制转换的可视性比较差,难以跟踪错误的转换,所以使用c++编程时,一般建议只有在C语言或标准C++之前的编译器上编写代码时,才使用这种语法。(c++ primer4中文版 p160)

c++的命名的强制类型转换的具体使用场合及方式:

以下部分转自:http://blog.xiaonei.com/GetEntry.do?id=404377356&owner=223128321

命名强制类型概述:

//reinterpret_cast将一个类型指针转换为另一个类型指针
//const_cast   用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,反过来也可以将一个非常量指针转换为一个常量指针变量
//static_cast   用于转换基本类型和具有继承关系的类新之间转换,不太用于指针类型的之间的转换
//dynamic_cast   只能在继承类对象的指针之间或引用之间进行类型转换
//以上只有dynamic_cast这种转换并非在编译时,而是在运行时,动态的。其它均在编译时

——————————————————————————————————————

#include<iostream.h>

int main(void)
{
//reinterpret_cast
//将一个类型指针转换为另一个类型指针,这种在转换不修改指针变量值数据存放格式
//只需在编译时重新解释指针的类型,他可以将指针转化为一个整型数但不能用于非指针的转换 
double d=9.3;
double* pd = &d;
int* pi = reinterpret_cast<int *> (pd);
class A{};
class B{};
A* pa = new A;
B* pb=reinterpret_cast<B*>(pa); //将pa转为B
long j=reinterpret_cast<long> (pa);//指针转换为整数
// int i=9;
// double x=reinterpret_cast<double>(i); //reinterpret_cast不能用于非指针的转换

//const_cast
//1.用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,
//2.反过来也可以将一个非常量指针转换为一个常量指针变量
//3.他无法将一个非指针的常量转换为普通变量
//example: const i=10;
//         int j=const_cast<int>(i); //无法转换 
const int ppp=998;

const int* pca=&ppp;
int* p=const_cast<int*>(pca);//将它转换为一个对应指针类型的普通变量,去除了const;

const A* paa=new A;
A * ppppa=const_cast<A*> (paa);//它转换为一个对应指针类型的普通变量,去除了const;

int * pii=0;//反过来也可以将一个非常量指针转换为一个常量指针变量
const int* piiic=const_cast<const int *>(pii);
//////////////////////////////////////////////////////////////////////////////////

//static_cast
//用于转换基本类型和具有继承关系的类新之间转换
//static_cast不太用于指针类型的之间的转换,他的效率没有reinterpret_cast的效率高

int in=99;
double dn=static_cast<double> (in);//用于转换基本类型和具有继承关系的类新之间转换 

class Base{};
class derv:public Base{};
derv dd;
Base bbbb=static_cast<Base>(dd);//具有继承关系的类新之间转换 
    
//static_cast不太用于指针类型的之间的转换,他的效率没有reinterpret_cast的效率高
Base *pb1=new Base;
derv *pder=static_cast<derv*>(pb1);//基类转继承类 
derv* pder1=new derv;
Base* pbase1=static_cast<Base*>(pder1);//继承类指针转父类指针 
//////////////////////////////////////////////////////////////////////////

//dynamic_cast
//1.只能在继承类对象的指针之间或引用之间进行类型转换
//2.这种转换并非在编译时,而是在运行时,动态的
//3.没有继承关系,但被转换的类具有虚函数对象的指针进行转换 
derv* dp=new derv;
Base* bv=dynamic_cast<Base *>(dp);//继承类对象的指针之间进行类型转换 

derv dpp;//继承类对象引用之间进行类型转换 
Base &b=dynamic_cast<Base&>(dpp);

class AA{virtual fun(){}
virtual ~AA(){}};
class BB{};

//没有继承关系,但被转换的类具有虚函数对象的指针进行转换,编译可通过 
AA* pAA=new AA;
BB* pBB=dynamic_cast<BB *>(pAA);

//没有继承关系,被转换的类也没有有虚函数对象的指针进行转换,编译不能通过 
BB* pBBB=new BB;
AA* pAAA=dynamic_cast<AA*>(pBBB);

return 1;
}

//总结:

标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。

static_cast
用法:static_cast < type-id > ( exdivssion ) 
该运算符把exdivssion转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。

注意:static_cast不能转换掉exdivssion的const、volitale、或者__unaligned属性。

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

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,

dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
class B{
public:
int m_iNum;
virtual void foo();
};

class D:public B{
public:
char *m_szName[100];
};

void func(B *pb){
D *pd1 = static_cast<D *>(pb);
D *pd2 = dynamic_cast<D *>((pb);
}

在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;
但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),
而pd2将是一个空指针。

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

另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。
class A{
public:
int m_iNum;
virtual void f(){}
};

class B:public A{
};

class D:public A{
};

void foo(){
B *pb = new B;
pb->m_iNum = 100;

D *pd1 = static_cast<D *>((pb); //compile error
D *pd2 = dynamic_cast<D *>((pb); //pd2 is NULL
delete pb;
}

在函数foo中,使用static_cast进行转换是不被允许的,

将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。

reinterpret_cast
用法:reinterpret_cast< type-id >(exdivssion)
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,
在把该整数转换成原类型的指针,还可以得到原先的指针值)。

该运算符的用法比较多。

const_cast 
用法:const_cast< type-id > (exdivssion)
该运算符用来修改类型的const或volatile属性。除了const或volatile修饰之外, type_id和exdivssion的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

Voiatile和const类试。举如下一例:
class B{
public:
int m_iNum;
}
void foo(){
const B b1;
b1.m_iNum = 100; //comile error
B b2 = const_cast<B>((b1);
b2. m_iNum = 200; //fine
}
上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;
使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。

C/C++类型转换总结的更多相关文章

  1. 为C# as 类型转换及Assembly.LoadFrom埋坑!

    背景: 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的: 之后,有小部分用户反映,工具用不了(没反应或有异常)~~~ 然后,建议小部分用户换个电脑 ...

  2. c# 基础 object ,new操作符,类型转换

    参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...

  3. Struts2日期类型转换

    针对日期类java.util.Date进行类型转换,要求客户端使用"yyyy-MM-dd","yyyy/MM/dd"中的任意一种输入,并以"yyyy- ...

  4. 【.NET深呼吸】基础:自定义类型转换

    照例,老周在开始吹牛之前,先讲讲小故事,这是朋友提出的建议,老TMD写技术有什么了不起的,人人都会写.后来老周想想,也确实,代码谁不会写,能写到有品位有感悟,就不容易做到.于是,老周接受了该朋友的建议 ...

  5. C++四种类型转换方式。

    类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...

  6. struts2类型转换

    1. Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概念除了用 ...

  7. C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》

    上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换. 一.隐式类型转换 在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符 ...

  8. Struts2入门(三)——数据类型转换

    一.前言 笔者一直觉得,学习一个知识点,你首先要明白,这东西是什么?有什么用?这样你才能了解.好了,不说废话. 1.1.类型转换为何存在?什么是类型转换? 在MVC框架中,都是属于表示层解决方案,都需 ...

  9. js条件判断时隐式类型转换

    Javascript 中,数字 0 为假,非0 均为真 在条件判断运算 == 中的转换规则是这样的: 如果比较的两者中有布尔值(Boolean),会把 Boolean 先转换为对应的 Number,即 ...

  10. JavaScript中数据类型转换总结

    JavaScript中数据类型转换总结 在js中,数据类型转换分为显式数据类型转换和隐式数据类型转换. 1, 显式数据类型转换 a:转数字: 1)Number转换: 代码: var a = " ...

随机推荐

  1. JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)

    (转载地址:http://technicolor.iteye.com/blog/1409656) 之前在<JavaScript小特性-面向对象>里面介绍过JavaScript面向对象的特性 ...

  2. opencl gauss filter优化(二)

    1.buffer使用image的方式:Horizontal 与 Vertical 算法一样, 共需30ms,wait time 19ms. const sampler_t sampler = CLK_ ...

  3. Tiny PXE Server简介

    Tiny PXE Server简介Tiny PXE Server是一款小巧而功能强大的网启软件.支持DHCP TFTP HTTP BINL DNS等多个协议,支持grub4dos,pxelinux,i ...

  4. ios CoreBluetooth 警告 is being dealloc'ed while pending connection

    ios CoreBluetooth 警告 is being dealloc'ed while pending connection CoreBluetooth[WARNING] <CBPerip ...

  5. 安卓App热补丁动态修复技术介绍

    版权声明:本文由johncz原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/169 来源:腾云阁 https://www.q ...

  6. SAP MM移动平均价和标准价逻辑

    从收货到领用,S一直都是以标准价格计算,V是实时更新 S 时将差异结转到在产品,产品中,最后结转到生产成本,最终到利润.具有计划性,可以控制考核 V 是实时更新,出现差异直接对应材料中调整.价格可以直 ...

  7. iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好

    转载: iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好 内容来自stack overflow的一个回答:ReactiveCocoa vs RxSwift – pros an ...

  8. Android LayoutParams

    LayoutParams继承于Android.View.ViewGroup.LayoutParams,就是布局. LayoutParams相当于一个Layout的信息包,它封装了Layout的位置.高 ...

  9. 解决点击a标签返回页面顶部的问题

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. ArcMap中"开始编辑"遇到一个或多个带有警告的图层“如果继续,可能无法编辑某些图层”的警告框

    开始编辑后可能出现的错误: 如果 ArcMap 在所选数据上启动编辑会话时遇到问题,将弹出一个对话框以提供附加信息.您可能会收到错误.警告或信息消息. 出现错误  时用户不可以启动任何编辑会话.只有解 ...