C++中的各式類型轉換

隱式轉換:

基本類型的隱式轉換:

當函數參數類型非精確匹配,但是可以轉換的時候發生

如:

void func1(double x){cout << x << endl;
}void func2(char c){cout << c << endl;
}int main(){func1(2);//int隱式轉換為doublefunc2(3);//int隱式轉換為charreturn 0;
}

自定義類型的隱式轉換:

函數參數列表接受類類型變量,傳入的單個參數不是類對象,但可以通過這個參數調用類對應的構造函數,那么編譯器就會將其隱式轉換為類對象

如:

class A{
private:int a;
public:A(int x):a{x}{}
};
void func(A a){cout << "func" << endl;
}int main(){func(1);//隱式將int轉換為A對象A obj = 1;//同上return 0;
}

多參數構造函數:

調用多參數構造函數時,將所有參數用用{}括起來,表示是一個初始化列表,但這并不屬于自定義類型隱式轉換,而是隱式構造

class A{
private:int a;
public:A(int x):a{x}{}
};class B{
private:A obj;int b;
public:B(A a,int x):obj{a},b{x}{}
};void func(B b){cout << "func" << endl;
}
int main(){func({A{1}, 2});//使用{A,int}隱式構造B對象func({1,2});//仍能運行,隱式將1轉換為A對象,然后用{A,int}隱式構造B對象return 0;
}

值得注意:

自定義的類型轉換不能連續發生兩次以上,否則會報錯

例如:

class A{
private:string str;
public:A(const string& s):str{s}{}
};void func(A a){cout << "func"<<endl;
}int main(){func("Hello");//報錯,因為需要將const char*隱式轉換為string,string轉換為const string,//再將string隱式轉換為A//需要發生兩次自定義類型隱式轉換func(string{"Hello"});//編譯通過,只需要string轉換為const string,再將string隱式轉換為A,//只發生一次自定義類型隱式轉換return 0;
}

禁止任何隱式調用的關鍵字:explicit

在類構造函數前加上explicit關鍵字,則該構造函數無法再被隱式轉換或隱式構造

從而防止某些錯誤的函數調用,比如想傳入int卻被隱式轉換為了類對象

class A{
public:explicit A(int x){cout << x << endl;}explicit A(int x,int y){cout << x << y << endl;}
};A func(int a,int b){return {a, b};//禁止{int,int}到A的隱式構造
}A func(int x){return A{x};//合法return A{x, x};//合法
}int main(){A a = 1;//禁止int到A的隱式轉換return 0;
}
好習慣:

將所有接受單個參數(包括多個參數,但只有一個參數沒有缺省值的)的構造函數都限定為explicit

拷貝構造和移動構造不應該限定為explicit

顯式轉換:

初始化列表式轉換:

使用type{var}的方式進行轉換,如int{'c'}

這種轉換只允許小范圍變量向大范圍變量轉換,不允許反向,如

int x{3.5};//不被允許截斷
long long y{3};
cout<<double{y}<<endl;//不允許被截斷

C風格轉換:

使用類似(int),或者int()的方式來轉換類型,底層是組合調用了C++的各種cast函數來進行轉換,因此不推薦使用這種轉換

在這種轉換中,嘗試的cast調用順序:

const_cast

static_cast

static_cast+const_cast

reinterpret_cast

reinterpret_cast+const_cast

const_cast轉換:

實際極少使用

使用方式:

const_cast<to_type>(var)

作用:

給變量添加/去除const屬性

如果該變量本身就是const變量,則無法真正地去除const屬性

例如:

int main(){const int x = 2;const int *p = &x;int *p2 = const_cast<int *>(p);*p2 = 3;cout << x << endl;cout << *p2 << endl;return 0;
}

輸出:

2
3

這里我們試圖去除p所指向的的變量的const屬性,并通過p2來修改其值,但在打印x時輸出的值仍為2,這是因為編譯器在編譯的時候知道x為const變量,因此將cout<<x直接優化成了cout<<2,從而保證了其不會被修改。

而我們嘗試使用p2去修改x的值,這屬于未定義行為,需避免。因此,對于本身為const屬性的變量,我們不應該使用const_cast來去除其const屬性,否則可能會導致未定義行為

const_cast用于去除本來不是const變量的const屬性

如:

void func(const int*p){int *p2 = const_cast<int *>(p);//用來去除被函數傳參過程中隱式添加的const屬性*p2 = 6;
}int main(){int x = 3;const int *p = const_cast<const int *>(&x);//人為為其添加const屬性,使其無法被修改//在經過了一段時間的應用后,現在又想修改x的值了int *p2 = const_cast<int *>(p);*p2 = 5;cout << *p << endl;func(&x);cout << *p << endl;return 0;
}

static_cast轉換:

使用方式:

static_cast<to_type>(var)

作用:

1.進行基本類型之間的轉換(允許截斷,告訴編譯器是有意為之的截斷)

相比之下,列表初始化轉化不允許截斷,因此更推薦使用static_cast進行轉換,當然程序員要負起截斷的責任,告訴大家這是有意為之的截斷,而不是自己大意導致的截斷

int x=static_cast<int>(3.14);

2.進行安全性檢查,不允許無關類型指針互轉

int main(){double x = 3.2;int *p2 = static_cast<int *>(&x);//不合法return 0;
}

3.可以將void*指針轉為任意類型指針

無安全性檢查,需要保證指向的類型正確(下例為不正確用法)

int main(){double x = 3.2;int *p2 = static_cast<int *>(static_cast<void*>(&x));//通過double*轉void*,再從void*轉到int*,跳過了安全性檢查return 0;
}

4.將派生類指針/引用/對象轉換為基類指針/引用/對象(向上轉換)

class Base{
};
class Derived:public Base{
};
int main(){Base *p_b = static_cast<Base *>(new Derived);Derived d;Base &ref_b = static_cast<Base &>(d);Base obj_b = static_cast<Base>(d);//導致對象切片
}

5.將基類指針/引用轉換為派生類指針/引用(向下轉換,不推薦)

無安全性檢查,需要保證基類指針指向要轉換的派生類或者其派生類

若基類派生類擁有虛函數,應優先使用dynamic_cast(下文講解)

Base* p_b2=new Derived;
Derived* p_d=static_cast<Derived*>(p_b2);//合法

6.顯式調用自定義構造函數/類型轉換函數進行轉換

class MyInt {
public:explicit MyInt(int x) : value(x) {}operator int() const { return value; }  // 自定義的轉換運算符
private:int value;
};MyInt mi = static_cast<MyInt>(42);  // 調用構造函數
int x = static_cast<int>(mi);       // 調用 operator int()

dynamic_cast轉換:

使用方式:

dynamic_cast<Derived_ptr/Derived_ref>(Base_ptr/Base_ref);

作用:

僅能對擁有虛函數的基類/派生類使用,且不能是protected/private繼承關系

基類為虛基類時,在某些情況會導致dynamic_cast失敗

對基類的指針/引用進行安全檢查的向下轉換(轉換為派生類指針/引用)

也可進行向上轉換(不推薦,應使用static_cast)

返回值:

若轉換成功,即Base_ptr/Base_ref實際指向的對象是Derived對象或者是其派生類對象,則返回指向該對象的Derived_ptr/Derived_ref

若轉換失敗,即Base_ptr/Base_ref實際指向的是別的東西,則返回nullptr

值得注意的是:

dynamic_cast依賴于RTTI(run-time type information)來確定指針指向對象的實際類型從而進行轉換,因此,沒有虛函數,或者關閉了RTTI優化,都會導致對象的RTTI信息丟失,從而導致dynamic_cast失敗

reinterpret_cast轉換:

該轉換無安全性檢查,直接重新解釋對象的二進制比特模式

高安全風險,極少使用,不推薦

使用方式:

reinterpret_cast<to_type>(var);

作用:

1.任意類型之間的指針互轉

2.指針與整數互轉

3.函數指針與數據指針互轉

4.任意數據類型互轉

路徑不確定導致的轉換二義性:

1.非虛繼承的菱形繼承的向上轉換:

此時將指向D對象的D指針向上轉換為A指針時,會出現二義性錯誤,因為編譯器不知道指向哪個A對象,這種情況下,只能一層一層地向上轉換,直到產生二義性的路徑消失,方可一次性轉換到A

2.虛繼承導致的菱形繼承的向下轉換:

此時將指向E對象的A指針向下轉換為B指針時,會出現二義性錯誤,因為編譯器不知道指向哪個B對象,而且虛繼承導致指針偏移無法計算(虛繼承機制以后的文章再講解),這種情況下,只能先轉成E指針,再向上轉換,直到二義性路徑消失

3.同層交叉cast轉換:

可以直接將指向E對象的D指針用dynamic_cast轉換為B指針

只需要滿足B和D沒有共同的虛基類即可(有的話,會導致指針偏移無法計算,從而dynamic_cast失敗),有的話,使用第二點的方法

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80831.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80831.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80831.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2.重建大師輸入輸出數據格式介紹

摘要&#xff1a;本文主要介紹重建大師支持的輸入數據格式及輸出數據格式。 1.輸入數據格式 1.1圖像文件 重建大師支持JPG、JPEG和TIFF格式的照片。 不同架次照片放置于同級目錄的不同文件夾&#xff0c;同一架次不同鏡頭拍攝得到的照片存放于不同的子文件夾&#xff0c;可使…

我們該如何使用DeepSeek幫我們減負?

在當今信息爆炸的時代&#xff0c;如何快速獲取、篩選和分析信息已經成為各行各業的重要能力。而DeepSeek作為一種先進的智能搜索和信息挖掘工具&#xff0c;能夠幫助用戶快速找到所需的信息&#xff0c;并從海量數據中提取出有用的洞見。在這篇博文中&#xff0c;我們將深入探…

抗量子計算攻擊的數據安全體系構建:從理論突破到工程實踐

在“端 - 邊 - 云”三級智能協同理論中&#xff0c;端 - 邊、邊 - 云之間要進行數據傳輸&#xff0c;網絡的安全尤為重要&#xff0c;為了實現系統總體的安全可控&#xff0c;將構建安全網絡。 可先了解我的前文&#xff1a;“端 - 邊 - 云”三級智能協同平臺的理論建構與技術實…

支付寶API-SKD-GO版

前言 支付寶api的sdk沒有提供go版&#xff0c;這里自己封裝了一個go版的sdk&#xff0c;有需要的朋友可以自取使用 支付寶 AliPay SDK for Go, 集成簡單&#xff0c;功能完善&#xff0c;持續更新&#xff0c;支持公鑰證書和普通公鑰進行簽名和驗簽。 Github地址 GitHub - …

JAVA研發+前后端分離,ZKmall開源商城B2C商城如何保障系統性能?

在電商行業競爭白熱化的當下&#xff0c;B2C 商城系統的性能表現成為決定用戶留存與商業成敗的關鍵因素。ZKmall 開源商城憑借 Java 研發與前后端分離架構的深度融合&#xff0c;構建起一套高效、穩定且具備強大擴展性的系統架構&#xff0c;從底層技術到上層應用全方位保障性能…

volatile是什么

一、背景和問題描述 假設你寫的這個多線程程序中&#xff0c;有兩個線程&#xff1a; 子線程&#xff08;thr&#xff09;&#xff1a;把flag變量設為1&#xff0c;并輸出“modify flag to 1”&#xff1b;主線程&#xff1a;一直在循環等待&#xff0c;直到flag變成1&#x…

MySQL的Docker版本,部署在ubantu系統

前言 MySQL的Docker版本&#xff0c;部署在ubantu系統&#xff0c;出現問題&#xff1a; 1.執行一個SQL&#xff0c;只有錯誤編碼&#xff0c;沒有錯誤提示信息&#xff0c;主要影響排查SQL運行問題&#xff1b; 2.這個問題&#xff0c;并不影響實際的MySQL運行&#xff0c;如…

專欄特輯丨懸鏡淺談開源風險治理之SBOM與SCA

隨著容器、微服務等新技術日新月異&#xff0c;開源軟件成為業界主流形態&#xff0c;軟件行業快速發展。但同時&#xff0c;軟件供應鏈也越來越趨于復雜化和多樣化&#xff0c;軟件供應鏈安全風險不斷加劇。 軟件供應鏈安全主要包括軟件開發生命周期和軟件生存運營周期&#x…

18.Excel數據透視表:第1部分創建數據透視表

一 什么是數據透視表 通過萬花筒可以用不同的方式査看里面畫面圖像&#xff0c;在excel中可以將數據透視表看作是對準數據的萬花筒&#xff0c;用不同角度去觀察數據&#xff0c;也可以旋轉數據&#xff0c;對數據進行重新排列&#xff0c;對大量的數據可以快速的匯總和建立交叉…

商業航天運動控制系統中的高可靠性芯片解決方案:挑戰、策略與應用研究

摘要&#xff1a;隨著商業航天領域的迅速發展&#xff0c;運動控制系統對芯片的可靠性提出了前所未有的挑戰。本文深入探討了商業航天運動控制系統中芯片可靠性面臨的挑戰&#xff0c;包括宇宙輻射效應、極端環境適應性及系統級可靠性保障等。同時&#xff0c;通過案例研究展示…

音視頻學習:使用NDK編譯FFmpeg動態庫

1. 環境 1.1 基礎配置 NDK 22b (r22b)FFmpeg 4.4Ubuntu 22.04 1.2 下載ffmpeg 官網提供了 .tar.xz 包&#xff0c;可以直接下載解壓&#xff1a; wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz tar -xvf ffmpeg-4.4.tar.xz cd ffmpeg-4.41.3 安裝基礎工具鏈 sudo …

前端開發避坑指南:React 代理配置常見問題與解決方案

前端開發避坑指南:React 代理配置常見問題與解決方案 一、為什么需要配置代理?二、使用 create-react-app 默認配置代理三、使用 http-proxy-middleware 配置復雜代理四、高級代理配置五、生產環境中的代理配置一、為什么需要配置代理? React 應用在開發過程中經常需要與后端…

用影刀RPA打通內容創作“最后一公里”:CSDN草稿一鍵同步多平臺發布

文章目錄 引言 一、需求場景&#xff1a;多平臺分發的效率困境1. 痛點分析2. 影刀RPA的破局價值 二、影刀RPA是啥&#xff1f;打工人逆襲神器&#xff01;三、手把手教你造"搬運工"——技術宅的土味開發日記第一步&#xff1a;當個"偷窺狂"——觀察手動操作…

進程與線程:09 進程同步與信號量

課程引入&#xff1a;進程同步與信號量 接下來這節課開始&#xff0c;我們再開始講多進程圖像。講多進程圖像的下一個點&#xff0c;前面我們講清楚了多進程圖像要想實現切換&#xff0c;調度是如何做的。同時&#xff0c;多個進程放在內存中&#xff0c;就會存在多進程合作的…

【愚公系列】《Manus極簡入門》036-物聯網系統架構師:“萬物互聯師”

&#x1f31f;【技術大咖愚公搬代碼&#xff1a;全棧專家的成長之路&#xff0c;你關注的寶藏博主在這里&#xff01;】&#x1f31f; &#x1f4e3;開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主&#xff01; &#x1f…

MySQL 8.0 OCP 英文題庫解析(四)

Oracle 為慶祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免費考取原價245美元的MySQL OCP 認證。 從今天開始&#xff0c;將英文題庫免費公布出來&#xff0c;并進行解析&#xff0c;幫助大家在一個月之內輕松通過OCP認證。 本期公布試題26~30 試題26:…

什么是原碼和補碼

補碼的本質確實是模運算&#xff08;Modular Arithmetic&#xff09;&#xff0c;這是理解補碼為何能統一加減法的核心數學原理。下面用最通俗的語言和例子解釋清楚&#xff1a; —### 1. 先理解什么是“模運算”- 模運算就是“周期性計數”&#xff0c;比如鐘表&#xff1a; -…

筆記項目 day02

一、用戶登錄接口 請求參數&#xff1a; 用loginDTO來封裝請求參數&#xff0c;要加上RequestBody注解 響應參數&#xff1a; 由于data里內容較多&#xff0c;考慮將其封裝到一個LoginUser的實體中&#xff0c;用戶登陸后&#xff0c;需要生成jwtToken并返回給前端。 登錄功…

2025年土木建筑與水利工程國際會議(ICCHE 2025)

2025 International Conference on Civil and Hydraulic Engineering (ICCHE 2025) &#xff08;一&#xff09;會議信息 會議簡稱&#xff1a;ICCHE 2025 大會地點&#xff1a;中國銀川 投稿郵箱&#xff1a;icchesub-paper.com 收錄檢索&#xff1a;提交Ei Compendex,CPCI,C…

運行Spark程序-在shell中運行1

&#xff08;一&#xff09;分布式計算要處理的問題 【老師提問&#xff1a;分布式計算要面臨什么問題&#xff1f;】 【老師總結】 分布式計算需要做到&#xff1a; 1.分區控制。把大的數據拆成一小份一小份的&#xff08;分區&#xff0c;分片&#xff09;讓多臺設備同時計算…