Skip to content

Instantly share code, notes, and snippets.

@lixingcong
Last active February 28, 2018 11:20
Show Gist options
  • Save lixingcong/21db1f1f0ce357215af424a052e3b2a8 to your computer and use it in GitHub Desktop.
Save lixingcong/21db1f1f0ce357215af424a052e3b2a8 to your computer and use it in GitHub Desktop.
Cast in C++
/*
static_cast<type>(var) 静态类型转换,编译的时c++编译器会做类型检查
基本类型(int,float...void*)能转换,通过继承关系的类之间也能相互转换
但是不能转换不同指针类型
*/
#include <iostream>
using namespace std;
struct S1{
int a,b;
char c[2];
};
class C1 {
public:
virtual ~C1(){}
virtual void f(){cout<<"I am C1"<<endl;}
};
class C2: public C1 {
public:
virtual void f(){cout<<"I am C2"<<endl;}
};
int main(int argc, char **argv) {
int i;
double d;
char c;
i=65;
cout<<"i="<<i<<endl;
cout<<endl;
// 隐式转换
c=i;
d=i;
// -------
d+=0.5;
cout<<"Implicit converting"<<endl;
cout<<"c="<<c<<endl;
cout<<"d="<<d<<endl;
cout<<endl;
// 使用static_cast进行C++风格的基本数据类型显式转换
c=static_cast<char>(i);
d=static_cast<double>(i);
// ----------------------------------------------
d+=0.5;
cout<<"Explicit converting (int -> char, int -> double)"<<endl;
cout<<"c="<<c<<endl;
cout<<"d="<<d<<endl;
cout<<endl;
S1 s1;
s1.a=100;
// 使用static_cast进行C++风格的void*显式转换
void* p_s1_void=static_cast<void*>(&s1);
S1* p_s1=static_cast<S1*>(p_s1_void);
// --------------------------------------
cout<<"Explicit converting (S1* -> void* -> S1*)"<<endl;
cout<<"p_s1->a="<<p_s1->a<<endl;
cout<<endl;
C2* c2=new C2;
// 使用static_cast进行C++风格的继承关系类之间显式转换
// 可以子类与基类相互指向,这里仅演示基类指针指向子类
C1* c1=static_cast<C1*>(c2);
// --------------------------------------
cout<<"Explicit converting (C2* -> C1*)"<<endl;
c1->f();
delete c2;
return 0;
}
/*
不同类型之间,进行强制类型转换,用reinterpret_cast<>() 进行重新解释
reinterpret_cast<>()很难保证移植性(数据大小端问题)
*/
#include <iostream>
using namespace std;
struct S1{
int a,b;
char c[2];
};
struct S2{
int a,b;
short c;
};
int main(int argc, char **argv) {
char buffer[]="aaaa";
cout<<"Explicit converting (char* -> short*)"<<endl;
short* p_short=reinterpret_cast<short*>(buffer);
cout<<"buffer="<<buffer<<endl;
cout<<"*p_short="<<*p_short<<endl;
cout<<endl;
S1* s1=new S1;
s1->c[0]='A';
s1->c[1]='\0';
cout<<"Explicit converting (S1* -> S2*)"<<endl;
S2* s2=reinterpret_cast<S2*>(s1);
cout<<"s1->c="<<s1->c<<endl;
cout<<"s2->c="<<s2->c<<endl;
cout<<endl;
delete s1;
return 0;
}
/*
动态类型转换,安全的基类和子类之间转换;运行时类型检查
*/
#include <iostream>
using namespace std;
class C1 {
public:
virtual ~C1(){}
};
class C2: public C1 {
int a;
};
const char HAVE[]="has";
const char HAVENOT[]="doesn't have";
int main(int argc, char **argv)
{
C1* c1 = new C1;
C2* c2 = new C2;
C2* c2_xxx;
try{
const char* does_have;
c2_xxx = dynamic_cast<C2*>(c1);
does_have=(nullptr != c2_xxx)?HAVE:HAVENOT;
cout << "c1 "<< does_have <<" type of C2.\n";
c2_xxx = dynamic_cast<C2*>(c2);
does_have=(nullptr != c2_xxx)?HAVE:HAVENOT;
cout << "c2 "<< does_have <<" type of C2.\n";
} catch (exception& e){
cout << "Exception: " << e.what();
}
delete c1;
delete c2;
return 0;
}
/*
去除或者添加变量的只读属性
*/
#include <iostream>
using namespace std;
void makeUpper(const char* c)
{
char* c_xxx=const_cast<char*>(c);
*c_xxx-=('a'-'A');
}
void makeConst(char* c)
{
const char* c_xxx=const_cast<const char*>(c);
cout<<"makeConst: "<<c_xxx<<endl;;
}
int main(int argc, char **argv)
{
char buffer[]="hello world!";
cout<<"lowerCase="<<buffer<<endl;
makeUpper(&buffer[0]);
cout<<"upperCase="<<buffer<<endl;
makeConst(buffer);
return 0;
}
@lixingcong
Copy link
Author

static_cast是您應該嘗試使用的第一個演員。 它實現類型之間的隱式轉換(如int到float或指向void*指針),它也可以調用顯式轉換函數(或隱式轉換函數)。 在許多情況下,明確說明static_cast不是必需的,但重要的是要注意, T(something)語法等同於(T)something ,應該避免(稍後再說)。 然而, T(something, something_else)是安全的,並且保證調用構造函數。

static_cast也可以通過繼承層次結構進行轉換。 向上(向基類)向上投射是不必要的,但是當向下投射時,只要不通過virtual繼承進行投射就可以使用它。 然而,它不會檢查,而是將層次結構中static_cast行為定義為實際上不是對像類型的類型。

const_cast可用於刪除或添加const到變量; 沒有其他C ++演員能夠刪除它(甚至沒有reinterpret_cast )。 重要的是注意,如果原始變量是const ,則修改以前的const值才是未定義的; 如果使用它來將const引用到沒有使用const聲明的東西,那麼它是安全的。 例如,當基於const成員函數重載時,這可能很有用。 它也可以用於向對象添加const ,例如調用成員函數重載。

const_cast也可以類似於volatile ,儘管不常見。

dynamic_cast幾乎專門用於處理多態。 您可以將任何多態類型的指針或引用轉換為任何其他類類型(多態類型至少有一個虛函數,聲明或繼承)。 您可以使用它不僅僅是向下傾斜 - 您可以側身傾斜,甚至連其他鏈條。 如果可能, dynamic_cast將尋找所需的對象並返回。 如果不能,就會在指針的情況下返回nullptr ,或者在引用的情況下拋出std::bad_cast 。

dynamic_cast有一些局限性。 如果在繼承層次結構中有多個相同類型的對象(所謂的“可怕的鑽石”)並且不使用virtual繼承,則不起作用。 它也只能通過公共繼承 - 它永遠不會通過protected或private繼承。 然而,這很少是一個問題,因為這種繼承形式是罕見的。

reinterpret_cast是最危險的演員,應該非常謹慎地使用。 它將一種類型直接轉換為另一種類型,例如將值從一個指針轉換到另一個指針,或將指針存儲在int或其他各種其他討厭的東西中。 很大程度上,通過reinterpret_cast獲得的唯一保證是,通常如果將結果轉換回原始類型,您將獲得完全相同的值(但如果中間類型小於原始類型,則不會 )。 還有一些reinterpret_cast不能做的轉換。 它主要用於特別奇怪的轉換和位操作,例如將原始數據流轉換為實際數據,或將數據存儲在對齊指針的低位。

原文链接

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment