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)只应用于类的指针和引用的转换中。
(3)dynamic_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,求a在X中的偏移量(不能声明struct变量)
面试官给的答案:&reinterpret_cast<struct X *>(0)->a
struct X
{
int a;
int b;
};
cout <<&reinterpret_cast<struct X*>(0)->b << endl;
输出:0x4