C++强制类型转换

1.C类型转换

C方式强制类型转换存在的问题:

任意类型之间都可以进行转换,编译器很难判断其正确性

在原码中无法快速定位所有使用强制类型转换的语句

在程序设计中强制类型转换是不被推荐的,与goto语句一样,应该避免。

static_cast   reinterpret_cast   const_cast   reinterpret_cast   static_cast

 

2.C++类型转换

C++将强制类型转换分为4种不同的类型

对于具有标准定义转换的简单类型而言工作的很好。

然而,这样的转换符也能不分皂白的应用于类(class)和类的指针。

ANSI-C++标准定义了四个新的转换符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 'const_cast',目的在于控制类(class)之间的类型转换。
代码:
reinterpret_cast<new_type>(expression)
dynamic_cast<new_type>(expression)
static_cast<new_type>(expression)
const_cast<new_type>(expression)

 

1.static_cast

-可以用于基本数据类型间的转化,但不能用于基本类型指针间的转换。

-还用于有继承关系类对象之间的转换和类指针之间的转换。类之间必须要有关系才能转换,所以没有关系的两个对象之间不能进行转换,转换也是没有任何意义的。

-应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类

是编译期间进行转换的,无法在运行时检测类型,所以类型之间的转换可能存在风险。

一般用dynamic_cast来代替这一功能。

 

 

dynamic_cast:主要用在类层次间的转换,还可以用于类之间的交换转换

具有类型检查的功能,比static_cast更安全

 

 

 

2.dynamic_cast

1其他三种都是编译时完成的dynamic_cast是运行时处理的,运行时要进行类型检查

2只应用于类的指针和引用的转换中。

3dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL

4使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。

        需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义

        这是由于运行时类型检查需要运行时类型信息而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,

        只有定义了虚函数的类才有虚函数表

dynamic_cast只用于的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程

不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。

也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:
class Base { virtual dummy() {} };
class Derived : public Base {};

Base* b1 = new Derived;
Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1);          // succeeds
Derived* d2 = dynamic_cast<Derived *>(b2);          // fails: returns 'NULL'

如果一个引用类型执行了类型转换并且这个转换是不可能的,一个bad_cast的异常类型被抛出:
代码:
class Base { virtual dummy() {} };
class Derived : public Base { };
Base* b1 = new Derived;
Base* b2 = new Base;
Derived d1 = dynamic_cast<Derived &*>(b1);          // succeeds
Derived d2 = dynamic_cast<Derived &*>(b2);          // fails: exception thrown

 

3.reinterpret_cast

有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。就是任意类型之间强制转换。

4.const_cast

const_cast操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。

C++const type& name是常变量                 const type name是常量

 

 

 

3.Demo分析

Demo1:子类指针转换成父类指针

static_cast和reinterpret_cast的区别主要在于多重继承,比如
class A { public: int m_a; };


class B { public: int m_b; };
class C : public A, public B {};

C c;
printf("%p, %p, %p\r\n", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));

 

C的内存结构是 m_a    m_b     先是m_a的地址  后是m_b的地址。

强制转换之后,两个B类的指针只能访问B中的成员。


  前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。


  因此, 你需要谨慎使用 reinterpret_cast.,它就是一般的强制转换,仅仅做简单的值转换。

 

用法:XXX_cast<type>(expression)

 

 

Dmeo2:父类指针转换成子类指针

 

class A

{

public:

int m_a;

};

 

class B

{

public:

int m_b;

B(){}

B(int b)

{

m_b = b;

}

};

class C:public A,public B

{

public:

C(int a,int b)

{

m_a = a;

m_b = b;

}

};

 

B b(10);

 

cout << reinterpret_cast<C*>(&b)->m_a << endl;

cout << reinterpret_cast<C*>(&b)->m_b << endl;

cout << "------------------------------------\n";

cout << static_cast<C*>(&b)->m_a << endl;

cout << static_cast<C*>(&b)->m_b << endl;

 

 

可以看出,static_cast会根据父类之类的内存位置做调整,而reinterpret_cast只是强制的转换,

 

 

 

 

 

 

Demo2

 已知有一个struct X,其中包括一个变量a,求aX中的偏移量(不能声明struct变量)

    面试官给的答案:&reinterpret_cast<struct X *>(0)->a

 

struct X

{

int a;

int b;

};

cout <<&reinterpret_cast<struct X*>(0)->b << endl;

 

输出:0x4

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值