C++:類型轉換

目錄

一、C語言中的類型轉換

二、為什么C++要新的轉換格式

三、 C++強制類型轉換

1.static_cast

2.reinterpret_cast?

3.const_cast

4.dynamic_cast?


一、C語言中的類型轉換

在C語言中,如果賦值運算符左右兩側類型不同,或者形參與實參類型不匹配,或者返回值類型與接收返回值類型不一致時,就需要發生類型轉化,C語言中總共有兩種形式的類型轉換:隱式類型轉換和顯式類型轉換。

  1. ?隱式類型轉化:編譯器在編譯階段自動進行,能轉就轉,不能轉就編譯失敗
  2. 顯式類型轉化:需要用戶自己處理
    void Test ()
    {int i = 1;int* p = &i;// 隱式類型轉換double d = i;printf("%d, %.2f\n" , i, d);// 顯示的強制類型轉換int address = (int) p;printf("%x, %d\n" , p, address);
    }

注意:一般關聯性強,表示的意義相近的變量可以隱式轉換,如int轉換成double;一般關聯性不強的一些內置類型可以顯示轉換,比如(void*)int轉換成void*;沒有關聯性的幾乎不能轉換。

缺陷:轉換的可視性比較差,所有的轉換形式都是以一種相同形式書寫,難以跟蹤錯誤的轉換

二、為什么C++要新的轉換格式

?C風格的轉換格式很簡單,但是有不少缺點的:

  • 隱式類型轉化有些情況下可能會出問題:比如數據精度丟失
  • 顯式類型轉換將所有情況混合在一起,代碼不夠清晰

我們舉個例子。

void insert(size_t pos, char ch)
{int end = 10;while (end >= pos){cout << end << endl;--end;}
}int main()
{insert(5, 'x');return 0;
}

這段代碼正常插入沒有問題,但當pos是0時,就會陷入“死循環”。

因為size_t是無符號整形,--變成-1,其實是size_t表示的最大無符號整數。

針對這些問題,C++提出了自己的類型轉化風格,因為C++要兼容C語言,所以C++中還可以使用C語言的轉化風格。

三、 C++強制類型轉換

標準C++為了加強類型轉換的可視性,引入了四種命名的強制類型轉換操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast 。

1.static_cast

?static_cast用于非多態類型的轉換(靜態轉換),編譯器隱式執行的任何類型轉換都可用static_cast,但它不能用于兩個不相關的類型進行轉換。

int main()
{double d = 12.34;int a = static_cast<int>(d);cout<<a<<endl;return 0;
}

2.reinterpret_cast?

reinterpret_cast操作符通常為操作數的位模式提供較低層次的重新解釋,用于將一種類型轉換為另一種不同的類型。

int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 這里使用static_cast會報錯,應該使用reinterpret_cast//int *p = static_cast<int*>(a);int *p = reinterpret_cast<int*>(a);return 0;
}

3.const_cast

const_cast最常用的用途就是刪除變量的const屬性,方便賦值

const_cast轉換中有一個細節需要注意,?請看下面代碼,

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

執行,

我們發現a的地址和p的值一樣,也就是p指向的空間就是a的值,可為什么p指向空間的值是3,a的值還是2呢,我們修改了*p,a的值也應該被修改了呀,a為什么沒有變?

因為const修飾的變量,編譯器會進行優化。正常const修飾的變量不會被修改,不會被修改就不用經常去內存中取,所以編譯器會把const修飾的值拷貝到寄存器,甚至用常量去替代,所以我們正常修改const_cast強制類型轉換“去const屬性的指針”,不會修改到內存中的const變量。

要想禁止編譯器對const變量的優化,可以在const前加一個關鍵字——volatile。

cv (const and volatile) type qualifiers - cppreference.com

?這樣我們運行,就可以修改到內存中a的值了,那么為什么a的地址是1呢?這是流插入(<<)的bug。

注意:流插入<<是指將程序中的數據插入到流中,輸出到屏幕或文件中或者其他流中;流提取>>是從流中提取數據到程序中。

我們可以用printf打印看一下,

printf打印就沒有問題,難道是類型識別錯誤,我們打印一下&a的類型。

?發現&a的類型是int const valatile*,

ostream::operator<< - C++ Reference (cplusplus.com)

可能編譯器類型匹配錯了,應該要匹配成指針類型的模板參數。我們強制轉換成指針類型看一下,

int* 和void*都可以,看來就是模板匹配錯誤。

?其實流插入還有一個缺點,就是當我們想打印字符的地址時,operator會匹配到字符類型的參數,從而打印的是字符而不是字符地址。

所以這里也必須強轉一下,?以上三種轉換都是C++對C語言轉換的規范。

4.dynamic_cast?

dynamic_cast用于將一個父類對象的指針/引用轉換為子類對象的指針或引用(動態轉換)

  • 向上轉型:子類對象指針/引用->父類指針/引用(不需要轉換,賦值兼容規則)
class A
{
public:virtual void f() {}int _a = 0;
};
class B : public A
{
public:int _b = 1;
};
int main()
{B objb;A obja = objb;A& ra = objb;//直接將objb繼承的部分切割給ra,中間沒有類型轉換double d = 1.1;const int& i = d;//隱式類型轉換,中間產生臨時變量,要const修飾return 0;
}
  • 向下轉型:父類對象指針/引用->子類指針/引用(用dynamic_cast轉型是安全的)

父類的指針或引用,轉換成子類的指針和引用,如果再用子類指針或引用訪問子類獨有的成員變量,就會造成越界訪問,如下:

class A
{
public:virtual void f() {}int _a = 0;
};
class B : public A
{
public:int _b = 1;
};
void fun(A* pa)
{//  向下轉換:直接轉換是不安全的// 如果pa是指向父類A對象,存在越界問題B* ptr = (B*)pa;ptr->_a++;ptr->_b++;//越界訪問
}int main()
{// 向下轉換規則:父類對象不能轉換成子類對象,但是父類指針和引用可以轉換子類指針和引用A a;B b;fun(&a);fun(&b);return 0;
}

為了防止這類越界,C++推出了dynamic_cast用于將一個父類指針或引用轉換。

dynamic_cast conversion - cppreference.com

class A
{
public:virtual void f() {}int _a = 0;
};class B : public A
{public:int _b = 1;
};void fun(A* pa)
{//  向下轉換:直接轉換是不安全的// 如果pa是指向父類A對象,存在越界問題B* ptr = dynamic_cast<B*>(pa);if (ptr){ptr->_a++;ptr->_b++;}else{cout << "轉換失敗" << endl;}
}int main()
{// 向下轉換規則:父類對象不能轉換成子類對象,但是父類指針和引用可以轉換子類指針和引用A a;B b;fun(&a);fun(&b);return 0;
}

調試一下可以看到,向上轉換時,程序輸出,

對于指針類型向上轉換會返回空指針,對于引用類型向上轉換dynamic_cast會拋異常std::bad_cast?。

當然,這有一個前提,“表達式是對多態類型 Base 的指針或引用,并且 target-type 是對 Derived 類型的指針或引用,則執行運行時檢查”。

四、RTTI

RTTI:Run-time Type identification的簡稱,即:運行時類型識別。

五、參考

ttps://blog.csdn.net/hp_cpp/article/details/104095700

RTTI、虛函數和虛基類的實現方式、開銷分析及使用指導 (baiy.cn)

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

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

相關文章

【高階數據結構】B-數、B+樹、B*樹的原理

文章目錄 B樹的概念及其特點解析B樹的基本操作插入數據插入數據模擬 分析分裂如何維護平衡性分析B樹的性能 B樹和B*樹B樹B樹的分裂B樹的優勢 B*B*樹的分裂 總結 B樹的概念及其特點 B樹是一顆多叉的平衡搜索樹&#xff0c;廣泛應用于數據庫和 文件系統中&#xff0c;以保持數據…

等保2.0的具體技術要求有哪些重點?

在數字化浪潮洶涌澎湃的當下&#xff0c;網絡安全猶如一座守護智慧之城的巍峨城墻&#xff0c;不可或缺。等級保護制度&#xff08;等保&#xff09;作為我國網絡安全戰略的基石&#xff0c;歷經歲月沉淀&#xff0c;已演進至2.0時代&#xff0c;即《網絡安全等級保護基本要求》…

算法思想總結:優先級隊列

一、最后一塊石頭的重量 . - 力扣&#xff08;LeetCode&#xff09; 我們每次都要快速找到前兩個最大的石頭進行抵消&#xff0c;這個時候用優先級隊列&#xff08;建大堆&#xff09;,不斷取堆頂元素是最好的&#xff01;每次刪除堆頂元素后&#xff0c;可以自動調整&#xf…

CentOS 7配置阿里云鏡像源及其加速

備份原yum源的配置&#xff1a;mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下載Centos-7.repo文件curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 清除及生成緩存 # 清除yum緩存 yum clean …

HarmonyOS - 通過.p7b文件獲取fingerprint

1、查詢工程所對應的 .p7b 文件 通常新工程運行按照需要通過 DevEco Studio 的 Project Structure 勾選 Automatically generate signature 自動生成簽名文件&#xff0c;自動生成的 .p7b 文件通常默認在系統用戶目錄下. 如&#xff1a;C:/Users/zhangsan/.ohos/config/default…

【Thread】python Thread Timer使用示例

import threading import time# 定義一個函數&#xff0c;它接受可變數量的字符串參數 def print_message(*messages):for message in messages:print(message)# 定義一個函數&#xff0c;它作為定時器線程的回調函數 def timer_thread(wait_time, *args):print(f"等待 {w…

JavaSE面試題(二)

目錄 一.為什么會有Java內存模型&#xff1f; 二.什么樣的情況下finally不會執行 三.鉤子是什么&#xff1f; 四.編譯時期的多態性和運行時期的多態性 五.談談反射機制 六.Java管道 本專欄全是博主自己收集的面試題&#xff0c;僅可參考&#xff0c;不能相信面試官就出這…

TCP報文校驗和(checksum)計算

一. 原理 將TCP相關內容&#xff08;TCP偽頭部TCP頭部TCP內容&#xff09;轉換成16比特的字符&#xff0c;然后進行累加&#xff0c;最后結果進行取反。TCP偽頭部是固定的&#xff0c;下文有相關代碼展示。 二. 源碼 源碼 #include <stdio.h> #include <stdlib.h&…

3D雞哥又上開源項目!單圖即可生成,在線可玩

大家好&#xff0c;今天和大家分享幾篇最新的工作 1、Unique3D Unique3D從單視圖圖像高效生成高質量3D網格&#xff0c;具有SOTA水平的保真度和強大的通用性。 如下圖所示 Unique3D 在 30 秒內從單視圖野生圖像生成高保真且多樣化的紋理網格。 例如屬于一張雞哥的打球寫真照 等…

js 遞歸調用 相同對象--數組遞歸調用

<div class="save-cl"> <a-button @click="saveCl" >保存為常用策略</a-button> </div> saveCl(){ console.log(this.form.filterList[0],--------常用策略)// 此對象為上圖對象 console.log(this.allElementsHaveValue(thi…

Windows的管理工具

任務計劃程序&#xff1a;這是一個用來安排任務自動運行的工具。你可以在這里創建新的任務&#xff0c;設定觸發條件&#xff0c;并指定任務的操作。 事件查看器&#xff1a;這是一套日志記錄和分析工具&#xff0c;&#xff0c;你可以了解到系統的工作狀況&#xff0c;幫助診…

損失函數篇

損失函數 1、邊界框損失函數/回歸損失函數bbox_loss 2、分類損失函數cls_loss 3、置信度損失函數obj_loss YOLOv8損失函數 1、概述 通過YOLOv8-訓練流程-正負樣本分配的介紹&#xff0c;我們可以知道&#xff0c;經過預處理與篩選的過程得到最終的訓練數據&#xff1a; a…

微信小程序/uniapp:class和style不生效的問題

非常重要&#xff1a;小程序端不支持 classObject 和 styleObject 語法。 文檔&#xff1a;https://uniapp.dcloud.net.cn/tutorial/vue-basics.html#class-與-style-綁定 目錄 對象語法數組語法字符串語法computed其他方案 對象語法 <!-- class --> <view class&quo…

AI是在幫助開發者還是取代它們?

在這個科技日新月異的時代&#xff0c;人工智能&#xff08;AI&#xff09;已經滲透到了我們生活的方方面面&#xff0c;尤其是在軟件開發和編程領域&#xff0c;其影響更是深遠。AI技術的飛速發展引發了廣泛討論&#xff1a;它究竟是開發者們的得力助手&#xff0c;還是未來可…

2024 年最佳 Figma 字體

字體不僅僅是文本字符&#xff0c;它們還塑造了用戶體驗。從引導用戶瀏覽界面到傳達品牌個性&#xff0c;字體對于設計??至關重要。然而&#xff0c;找到適合您的網站或應用風格的完美字體可能具有挑戰性。 但不要害怕&#xff0c;我們會幫助您&#xff01;請繼續關注&#x…

C語言 指針和數組——指針的算術運算

目錄 指針的算術運算 指針加上一個整數 指針減去一個整數 指針相減 指針的關系比較運算 小結 指針的算術運算 指針加上一個整數 指針減去一個整數 指針相減 指針的關系比較運算 小結 ? 指針變量 – 指針類型的變量&#xff0c;保存地址型數據 ? 指針變量與其他類型…

負載均衡(服務器)

vi /etc/sysconfig/network-scripts/ifcfg-ens33 systemctl restart network 防火墻 systemctl stop firewalld systemctl disable firewalld vi /etc/selinux/config setenforce 0 yum install gcc gcc-c mkdir /lnmp cd /lnmp/ tar -zxvf zlib-1.2.12.tar.gz tar -zxv…

在Ubuntu 16.04上安裝和配置ownCloud的方法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到網站。 簡介 ownCloud 是一個文件共享服務器&#xff0c;允許您將個人內容&#xff08;如文檔和圖片&#xff09;存儲在一個類似 Dropbox 的集…

[C++][CMake][CMake基礎]詳細講解

目錄 1.CMake簡介2.大小寫&#xff1f;3.注釋1.注釋行2.注釋塊 4.日志 1.CMake簡介 CMake是一個項目構建工具&#xff0c;并且是跨平臺的 問題 – 解決 如果自己動手寫Makefile&#xff0c;會發現&#xff0c;Makefile通常依賴于當前的編譯平臺&#xff0c;而且編寫Makefile的…

vue的學習--day3

1、嘗試使用json文件模擬增刪改查 json server:準備一份自己的數據&#xff08;這里我用的是老師給的&#xff09;。 轉到d盤&#xff0c;然后打開json文件&#xff1a; 下面模擬增刪改查&#xff1a; 借助工具postman或apifox或apipost&#xff1a; 這里我下載了apifox&…