網站首頁 編程語言 正文
在C++中,我們經常使用到類型的轉換,像把一個int類型轉換成char類型,一個int類型轉換成double類型,這些轉換屬于隱式類型轉換。而今天我們要來講的是顯式類型轉換。C++提供了四種顯式類型轉換,分別是:static_cast、dynamic_cast、const_case、reinterpret_case。
一、static_case
static_case的定義為:
static_case<type_name>(expression)
type_name是轉換的類型,expression是被轉換的對象或者表達式。
static_case一般用于隱式轉換,當type_name和express至少有一方可以隱式轉換時,則可以用static進行強制類型轉換。可以用于常見的int、float、double等類型轉換;轉換成功返回true,否則返回false(相當于C語言中的強制類型轉換)。
1、基本數據類型轉換
double serven_double_1 = 1.2;
std::cout<<serven_double_1<<std::endl;
int serven_int_1 = static_cast<int>(serven_double_1);
std::cout<<serven_int_1<<std::endl;
double serven_double_2 = static_cast<double>(serven_int_1);
std::cout<<serven_double_2<<std::endl;
運行結果:基本類型的轉換,可以看到double類型轉換成int類型后丟失了精度,這一點跟reinterpret_case不一樣,reinterpret_case是底層二進制的強制拷貝和語義轉換,所以不會丟失精度,后面會講到。
2、指針和void指針的轉換
int* serven_int_2 = new int(2);
void * serven_void_1 = static_cast<void*>(serven_int_2);
int *serven_int_3 = static_cast<int*>(serven_void_1);
*serven_int_2 = 6;
std::cout<<*serven_int_2<<std::endl;
std::cout<<*serven_int_3<<std::endl;
std::cout<<serven_void_1<<std::endl;
std::cout<<serven_int_2<<std::endl;
std::cout<<serven_int_3<<std::endl;
?運行結果:void指針和其他類型的指針進行轉化的時候,他們都是指向同一個地址。
?3、父類和子類之間的轉換
class SERVEN_PARENT{
public:
SERVEN_PARENT(){}
void Function(){
std::cout<<"PARENT"<<std::endl;
}
};
class SERVEN_CHILD : public SERVEN_PARENT{
public:
SERVEN_CHILD(){}
void Function(){
std::cout<<"CHILD"<<std::endl;
}
};
void main(){
SERVEN_PARENT* ser_par = new SERVEN_PARENT();
ser_par->Function();
SERVEN_CHILD* ser_chi = static_cast<SERVEN_CHILD*>(ser_par);
ser_chi->Function();
}
運行結果:在main函數第二行中定義了一個ser_chi,是一個派生類對象,然后強制將基類對象轉換成子類,這種叫做下行轉換,轉換后打印的結果是子類的Function,使用static_case來進行向下轉換是不安全的,因為當子類中定義了基類沒有的變量,并且在Function函數中使用了這個變量,那么程序將會報錯。
?下面我們來看一下static_case不安全的例子:
class SERVEN_PARENT{
public:
SERVEN_PARENT(){}
void Function(){
std::cout<<"PARENT"<<std::endl;
}
};
class SERVEN_CHILD : public SERVEN_PARENT{
public:
SERVEN_CHILD(){}
void Function(){
std::cout<<"CHILD"<<std::endl;
std::cout<<nums<<std::endl;
}
private:
char nums = 'g';
};
void main(){
SERVEN_PARENT* ser_par = new SERVEN_PARENT();
ser_par->Function();
SERVEN_CHILD* ser_chi = static_cast<SERVEN_CHILD*>(ser_par);
ser_chi->Function();
}
?運行結果:因為派生類對象使用了自己獨有的變量,所以打印char字符的時候就出現了亂碼。
二、dynamic_case
dynamic_case的定義為:
dynamic<type_name>(expression)
type_name是轉換的類型,expression是被轉換的對象或者表達式。
dynamic一般用于基類指向派生類時的強制轉換,轉換成功返回true,失敗返回false。它不像static_case一樣向下轉換不安全,它是安全的。它的安全性體現在RTTI,那什么是RTTI呢?
RTTI是運行時類型識別。程序能夠使用基類的指針或引用來檢查著這些指針或引用所指的對象的實際派生類型(判斷指針原型)。RTTI提供了兩個非常有用的操作符:typeid和dynamic_cast。(三個最主要的東西,dynamic_cast,typeid,type_info)。typeid:typeid函數(為type_info類的友元函數,為什么要這樣呢?目的是防止創建type_info對象)的主要作用就是讓用戶知道當前的變量是什么類型的,它可以返回一個type_info的引用,可以獲取類的名稱和編碼typeid重載了type_info中的==和!=可以用于判斷兩個類型是否相等。
dynamic_case和static_case在類繼承的區別就是dynamic_case向下轉換是安全的。
三、const_case
const_case的定義為:
const_case<type_name>(expression)
type_name是轉換的類型,expression是被轉換的對象或者表達式。
const_case有兩個功能,分別是去掉const和加上const,一般用于去掉const,修改被const修飾為常量的值。但是修改的這個值本身不能是const常量,而是被二次引用或者傳參數時被引用為const,才能修改,否則修改失敗。同時type和express兩個類型要一直去掉const,修改成功返回true,否則返回false。
1、加上const
int* serven_int_4 = new int(2);
const int* serven_int_5 = const_cast<const int*>(serven_int_4); // 轉換為常量指針
*serven_int_4 = 3;
//*serven_int_5 = 4; // 不能修改
std::cout<<*serven_int_4<<std::endl;
std::cout<<*serven_int_5<<std::endl;
std::cout<<serven_int_4<<std::endl;
std::cout<<serven_int_5<<std::endl;
2、去掉const
(1)const修飾指針,指針指向一個類對象(常量指針)
將一個常量指針轉換成非常量指針。
class SERVEN_PARENT{
public:
SERVEN_PARENT(){}
void Function(){
std::cout<<"PARENT"<<std::endl;
}
};
class SERVEN_CHILD : public SERVEN_PARENT{
public:
SERVEN_CHILD(){}
void Function(){
std::cout<<"CHILD"<<std::endl;
std::cout<<nums<<std::endl;
}
private:
char nums = 'g';
};
void main(){
SERVEN_PARENT ser_par;
const SERVEN_PARENT* pP = &ser_par;
SERVEN_PARENT* pP_1 = const_case<SERVEN_PARENT*>(pP); // 強制將pP轉換成非const
}
(2)const修飾指針指向對象的數值(指針常量)
將指針常量轉換為非指針常量。
void main(){
SERVEN_PARENT ser_par;
SERVEN_PARENT* const pP = &ser_par;
SERVEN_PARENT* pP_1 = const_case<SERVEN_PARENT*>(pP); // 強制將pP轉換成非const
}
(3)const修飾指針指向對象的數值并且修飾指針(常量指針常量)
常量指針常量可以被轉換為非常量指針常量,也可以轉換成指針常量或者常量指針。
void main(){
SERVEN_PARENT ser_par;
const SERVEN_PARENT* const pP = &ser_par;
SERVEN_PARENT* pP_1 = const_case<SERVEN_PARENT*>(pP); // 強制將pP轉換成非const
const SERVEN_PARENT* pP_2 = const_case<SERVEN_PARENT*>(pP); // 強制將pP轉換成常量指針
SERVEN_PARENT* const pP_2 = const_case<SERVEN_PARENT*>(pP); // 強制將pP轉換成指針常量
}
四、reinterpret_case
reinterpret_case的定義為:
reinterpret_case<type_name>(expression)
type_name是轉換的類型,expression是被轉換的對象或者表達式。
reinterpret_case是一種比較粗暴的轉換方式,并且是最不安全的,為什么說它粗暴呢?因為它直接去拷貝最底層的二進制,它的本質是編譯器的指令,它的作用是可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針。或者不同類型的指針相互轉換。
double serven_double_2 = 1.20;
char* serven_char_1 = reinterpret_cast<char* >(&serven_double_2);
double* serven_double_3 = reinterpret_cast<double*>(serven_char_1);
std::cout<<*serven_double_3<<std::endl;
int* serven_int_6 = reinterpret_cast<int*>(&serven_double_2);
double* serven_double_4 = reinterpret_cast<double*>(serven_int_6);
std::cout<<*serven_double_3<<std::endl;
運行結果:我們可以看到reinterpret_case將double類型轉換成int,再轉換成double類型后精度不會丟失,而static_case會丟失。
原文鏈接:https://blog.csdn.net/weixin_43340455/article/details/124595862
相關推薦
- 2022-10-17 C++STL教程之vector模板的使用_C 語言
- 2023-07-31 element中el-input無法輸入
- 2022-09-22 set數據結構/map數據結構(ES6)
- 2022-05-11 在 WebStorm 中誤添加自定義的 HTML 屬性,如何刪除
- 2022-05-14 實現AJAX異步調用和局部刷新的基本步驟_AJAX相關
- 2022-10-05 Redis實現數據的交集、并集、補集的示例_Redis
- 2023-03-02 golang中new與make的區別講解_Golang
- 2022-04-25 jquery實現表格行的上下移動和置頂_jquery
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支