color:rgb(51,51,51)">呵呵c;今天来好好看看着几个转换操作符的用法。以前老是看着眼熟c;但是用着手生。今天决定搞定这些个东西。
color:rgb(51,51,51)">在Cclass="tags" href="/tags/YuYan.html" title=语言>语言中类型转换有几种方式:
color:rgb(51,51,51)">1. (expression). 在表达式外边加括号c;由class="tags" href="/tags/BianYiQi.html" title=编译器>编译器来决定怎么改变。
color:rgb(51,51,51)">2. new_type(expression). 强制类型括号住表达式。
color:rgb(51,51,51)">3. (new_type)expression. 括号住强制类型。
color:rgb(51,51,51)">4. Cclass="tags" href="/tags/YuYan.html" title=语言>语言允许的内置转换。
color:rgb(51,51,51)">这些转换非常高效c;我非常喜欢使用。特别是在指针转换和数值转换时用到的非常多。只要编写程序的人知道自己要做什么转换c;并知道应该怎样转换的话c;我认为上边的转换方式非常之好。但是没有清楚的了解每个转换的细节的话c;就有可能出现问题c;比如指针指向不应该指向的区域:出现野指针或者指向位置错误(主要是对内存结构不了解)c;或者计算数值被截去等问题发生。
color:rgb(51,51,51)">C++程序兼容Cclass="tags" href="/tags/YuYan.html" title=语言>语言的转化c;但是针对面向对象class="tags" href="/tags/YuYan.html" title=语言>语言的特性c;设计了以下几个类型转换操作符。他们的出现是为了Cclass="tags" href="/tags/YuYan.html" title=语言>语言类型转换中语义模糊和固有的危险陷阱c;因为Cclass="tags" href="/tags/YuYan.html" title=语言>语言不去判断所要操作的类型转换是否合理。
color:rgb(51,51,51)">static_cast:用于非多态类型的转换。
color:rgb(51,51,51)">dynamic_cast:用于多态类型的转换。
color:rgb(51,51,51)">const_cast:用来消除const, volatile, __unaligned属性的转换。
color:rgb(51,51,51)">reinterpret_cast:用于空间的重新解释。
color:rgb(51,51,51)">还有一个在VS2005中出现的类型转换关键字safe_cast.#2
color:rgb(51,51,51)">
color:rgb(51,51,51)">static_cast:
color:rgb(51,51,51)">static_cast<type_id>(expression)
color:rgb(51,51,51)">这个关键字可以用来将一个指针转换为父类的指针也可以转换为子类的指针或者基本的类型转换。但是这种转换是强制的c;并没有任何运行时类型检查来保证转换的正确性c;所以编写代码的人需要明白自己所进行的转换是否合理。
color:rgb(51,51,51)">//基本类型的转换
color:rgb(51,51,51)">enum e { A = 1, B, C };
color:rgb(51,51,51)">double d = 12.25;
color:rgb(51,51,51)">unsigned int ui = 25;
color:rgb(51,51,51)">char c = static_cast<char>(ui);
color:rgb(51,51,51)">int i = static_cast<int>(d);
color:rgb(51,51,51)">int j = static_cast<int>(B);
color:rgb(51,51,51)">//父类子类转换
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class F //father
color:rgb(51,51,51)">{
color:rgb(51,51,51)">public:
color:rgb(51,51,51)"> int _father;
color:rgb(51,51,51)">};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class S : public F //son
color:rgb(51,51,51)">{
color:rgb(51,51,51)">public:
color:rgb(51,51,51)"> _son;
color:rgb(51,51,51)">};
color:rgb(51,51,51)">F *pFather = new F();
color:rgb(51,51,51)">S *pSon = new S();
color:rgb(51,51,51)">F *pF;
color:rgb(51,51,51)">S *pS;
color:rgb(51,51,51)">pF = static_cast<F *>(pSon); //将子类指针转换为父类指针c;OK
color:rgb(51,51,51)">pS = static_cast<S *>(pFather); //将父类指针转换为子类指针c;错误
color:rgb(51,51,51)">第二个错误的转换不是说class="tags" href="/tags/BianYiQi.html" title=编译器>编译器编译不过去c;而是运行时会出现错误。
color:rgb(51,51,51)">原因如下:假设pF指向了pSon的位置c;它可以访问_fatherc;它找不到_sonc;这样没有问题。但是pS指向了pFather的位置c;它访问_father没有问题c;但是访问_son时就会产生错误c;因为pFather根本没有_son这个变量。
color:rgb(51,51,51)">下面是将父类转换为子类指针时c;static_cast和dymanic_cast两者不同的表现:
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class F
color:rgb(51,51,51)">{
color:rgb(51,51,51)">public:
color:rgb(51,51,51)"> virtual void speak(){};
color:rgb(51,51,51)"> int i;
color:rgb(51,51,51)">};
color:rgb(51,51,51)">
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class S : public F
color:rgb(51,51,51)">{
color:rgb(51,51,51)">public:
color:rgb(51,51,51)"> void speak()
color:rgb(51,51,51)"> {
color:rgb(51,51,51)"> cout << "S = " << _s << endl;
color:rgb(51,51,51)"> }
color:rgb(51,51,51)"> double _s;
color:rgb(51,51,51)">};
color:rgb(51,51,51)">F *pF = new F();
color:rgb(51,51,51)">S *pS = static_cast<S*>(pF);
color:rgb(51,51,51)">pS->speak();
color:rgb(51,51,51)">S1 *pDS = dynamic_cast<S*>(pF);
color:rgb(51,51,51)">pDS->speak();
color:rgb(51,51,51)">静态的转换编译不显示警告c;运行结果不输出(调用F的speak函数)。动态的转换编译显示可能出现不可预期的结果c;运行时崩溃。(VS2005时c;返回空指针c;但是不会崩溃。我认为要是按照C++的特性还是崩溃比较好一点c;让程序员容易理解这么做是错误的。)
color:rgb(51,51,51)">
color:rgb(51,51,51)">dynamic_cast:
color:rgb(51,51,51)">dynamic_cast<type_id>(expression)
color:rgb(51,51,51)">本关键字主要处理多态的类型转换c;type_id要么是指针类型c;要么是引用类型要么是void*。当type_id为指针和void*时c;expression必须是type_id类型的指针c;当type_id为引用时c;expression也必须是type_id类型的引用。#1
color:rgb(51,51,51)">
color:rgb(51,51,51)">1.最常用的用法就是将子类指针转换为父类指针。(不举例)
color:rgb(51,51,51)">2.当type_id为void*时c;指针指向整个对象的空间。
color:rgb(51,51,51)">Class A;
color:rgb(51,51,51)">A *pA = new A();
color:rgb(51,51,51)">void *p = dynamic_cast<void*>(pA);
color:rgb(51,51,51)">但是type_id不为void*时c;计算机就要在运行时检查是否能够转换。
color:rgb(51,51,51)">3.跳级转换。
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class B : public A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class C : public B{};
color:rgb(51,51,51)"> A *pA;
color:rgb(51,51,51)"> B *pB;
color:rgb(51,51,51)"> C *pC = new C();
color:rgb(51,51,51)"> pB = dynamic_cast<B*>(pC); //逐级转换OK
color:rgb(51,51,51)"> pA = dynamic_cast<A*>(pB); //逐级转换OK
color:rgb(51,51,51)"> 或者
color:rgb(51,51,51)"> pA = dynamic_cast<A*>(pC); //跳级转换OK
color:rgb(51,51,51)"> delete pC;
color:rgb(51,51,51)">以下情况跳级转换不可以:
color:rgb(51,51,51)">
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class B : public A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class C : public A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class D : public B, public C{};
color:rgb(51,51,51)"> A *pA;
color:rgb(51,51,51)"> D *pD = new D();
color:rgb(51,51,51)"> pA = dynamic_cast<A*>(pB); //出现错误c;是不行的c;原因大家都清楚。
color:rgb(51,51,51)">
color:rgb(51,51,51)">
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class B : public A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class C : public A{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class D : public B{};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class E : public C, public D{};
color:rgb(51,51,51)"> A *pA;
color:rgb(51,51,51)"> B *pB;
color:rgb(51,51,51)"> E *pE = new E();
color:rgb(51,51,51)"> pB = dynamic_cast<B*>(pE);
color:rgb(51,51,51)"> pA = dynamic_cast<A*>(pB); //可以
color:rgb(51,51,51)"> pA = dynamic_cast<A*>(pE); //不可以c;原因是很简单的。
color:rgb(51,51,51)"> delete pE;
color:rgb(51,51,51)">4.两个不相干的类之间转换。
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class A {};
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class B {};
color:rgb(51,51,51)"> A* pa = new A;
color:rgb(51,51,51)"> B* pb = dynamic_cast<B*>(pa); // 不可以c;没有相互转换的基础
color:rgb(51,51,51)">但是reinterpret_cast可以转换c;可以参考reinterpret_cast
color:rgb(51,51,51)">
color:rgb(51,51,51)">
color:rgb(51,51,51)">const_cast:
color:rgb(51,51,51)">const_cast<type_id>(expression)
color:rgb(51,51,51)">这个关键字消除了几个关键字的作用const, volatile,和__unaligned的作用。const经常使用。MSDN有const的例子照抄过来。
color:rgb(51,51,51)">class="tags" href="/tags/CLASS.html" title=class>class CCTest {
color:rgb(51,51,51)">public:
color:rgb(51,51,51)"> void setNumber( int );
color:rgb(51,51,51)"> void printNumber() const;
color:rgb(51,51,51)">private:
color:rgb(51,51,51)"> int number;
color:rgb(51,51,51)">};
color:rgb(51,51,51)">void CCTest::setNumber( int num ) { number = num; }
color:rgb(51,51,51)">void CCTest::printNumber() const {
color:rgb(51,51,51)"> cout << "/nBefore: " << number;
color:rgb(51,51,51)"> const_cast< CCTest * >( this )->number--;//这里消除了const的作用
color:rgb(51,51,51)"> cout << "/nAfter: " << number;
color:rgb(51,51,51)">}
color:rgb(51,51,51)">int main() {
color:rgb(51,51,51)"> CCTest X;
color:rgb(51,51,51)"> X.setNumber( 8 );
color:rgb(51,51,51)"> X.printNumber();
color:rgb(51,51,51)">}
color:rgb(51,51,51)">
color:rgb(51,51,51)">reinterpret_cast:
color:rgb(51,51,51)">reinterpret_cast
color:rgb(51,51,51)">这个关键字比较“强悍”c;随意转换类型。但是转换错误c;就是你的不对了。呵呵c;我的原则两个字:“慎用”。
color:rgb(51,51,51)">这个关键字可以在任何类型的指针之间转换。
color:rgb(51,51,51)">不可以替代const_cast。
color:rgb(51,51,51)">不提供安全转换。
color:rgb(51,51,51)">MSDN的例子显示出来它的强悍c;也显示出了他的脆弱。只要你一个不小心就会乱用。
color:rgb(51,51,51)">#include <iostream>
color:rgb(51,51,51)">
color:rgb(51,51,51)">// Returns a hash code based on an address
color:rgb(51,51,51)">unsigned short Hash( void *p ) {
color:rgb(51,51,51)"> unsigned int val = reinterpret_cast<unsigned int>( p );
color:rgb(51,51,51)"> return ( unsigned short )( val ^ (val >> 16));
color:rgb(51,51,51)">}
color:rgb(51,51,51)">
color:rgb(51,51,51)">using namespace std;
color:rgb(51,51,51)">int main() {
color:rgb(51,51,51)"> int a[20];
color:rgb(51,51,51)"> for ( int i = 0; i < 20; i++ )
color:rgb(51,51,51)"> cout << Hash( a + i ) << endl;
color:rgb(51,51,51)">}