C/C++類型轉換

C/C++類型轉換

1. C類型轉換

C 語言中的類型轉換主要分為兩種:

  1. 隱式類型轉換 (Implicit Conversion)?- 由編譯器自動完成。

  2. 顯式類型轉換 (Explicit Conversion)?- 由程序員強制指定,也稱為強制類型轉換

1.2 隱式類型轉換

編譯器在編譯時自動進行的轉換,通常發生在不同數據類型的變量混合運算、賦值或函數調用時。

轉換規則(通常遵循向上轉換原則):

int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double

常見發生的場景

int i = 10;
float f = 3.14;
double d = i + f; // i 被自動轉換為 float 參與運算,結果再轉換為 double 賦值給 d

1.3 強制類型轉換

當用戶需要明確地將一種數據類型轉換為另一種時使用。它使用強制類型轉換運算符,語法是在要轉換的目標類型前加上括號,然后放在值或表達式前面。

常見發生的場景

int a = 5, b = 2;
float result;
result = a / b;       // 錯誤:結果是 2.0 (整數除法)
result = (float)a / b; // 正確:結果是 2.5。將 a 轉為 float,b 也會被隱式轉換為 float

將 void 指針轉換為具體類型指針:

void* generic_ptr;
int* int_ptr;
int x = 10;generic_ptr = &x;          // 合法:任何指針都可以賦值給 void*
// *generic_ptr;           // 錯誤:不能對 void* 解引用
int_ptr = (int*)generic_ptr; // 必須強制轉換回 int*
printf("%d\n", *int_ptr);    // 輸出 10

注意:?在 C 語言中,從?void*?轉換到其他指針類型必須使用強制轉換,而在 C++ 中?static_cast?可以完成這個工作,并且從?void*?到其他指針類型的隱式轉換在 C++ 中是非法的。

2. C++中的類型轉換

2.1 隱式類型轉換

  • C++支持內置類型向自定義類型之間的轉換,內置類型轉換為自定義類型需要構造函數的支持。

  • C++支持自定義類型轉換為內置類型,通過運算符重載 operator type () 的函數支持。

  • C++支持自定義類型向自定義類型之間的轉換,需要對應類型的構造函數支持。

2.1.1 內置類型 -> 自定義類型(通過構造函數)
#include <iostream>class Meter {
private:double value;
public:// 關鍵:接收單一參數的構造函數// 定義了從 double -> Meter 的轉換規則Meter(double val) : value(val) {std::cout << "構造函數被調用,將 double " << val << " 轉換為 Meter" << std::endl;}
};int main() {Meter m1 = 5.7;     // 隱式轉換:double -> Meterreturn 0;
}

注意:?使用?explicit?關鍵字可以禁止隱式轉換,只允許顯式轉換

2.1.2 自定義類型 -> 內置類型(通過轉換函數)

通過在類中定義?operator type()?成員函數,可以實現從自定義類型到內置類型的轉換。

#include <iostream>class Meter {
private:double value;
public:Meter(double val) : value(val) {}// 轉換函數:Meter -> doubleoperator double() const {std::cout << "轉換函數被調用,將 Meter 轉換為 double: " << value << std::endl;return value;}
};int main() {Meter m(5.7);// 自定義類型 -> 內置類型double length_in_double = m;  // 隱式調用 operator double()std::cout << "轉換為 double 的值: " << length_in_double << std::endl;return 0;
}

通過operator bool()函數,可以將自定義類型當作判斷條件。

2.1.3 自定義類型 -> 自定義類型(通過構造函數或轉換函數)
#include <iostream>class Kilometer; // 前向聲明class Meter {
private:double value;
public:Meter(double val) : value(val) {}double getValue() const { return value; }// 也可以定義到 Kilometer 的轉換函數// operator Kilometer() const;
};class Kilometer {
private:double value;
public:Kilometer(double val) : value(val) {}// 關鍵:定義接收 Meter 參數的構造函數// 提供了 Meter -> Kilometer 的轉換路徑Kilometer(const Meter& m) : value(m.getValue() / 1000.0) {std::cout << "Kilometer 構造函數:將 Meter 轉換為 Kilometer" << std::endl;}void display() const {std::cout << value << " kilometers" << std::endl;}
};// Meter 中轉換函數的實現
// Meter::operator Kilometer() const {
//     return Kilometer(value / 1000.0);
// }int main() {Meter m(1500.0); // 自定義類型 -> 自定義類型Kilometer km = m; // 隱式轉換:Meter -> Kilometerkm.display();     // 輸出: 1.5 kilometersreturn 0;
}

對于轉換函數,也可以使用?explicit?關鍵字來禁止隱式轉換:

explicit operator double() const {return value;
}Meter m(5.7);
double d1 = m;          // 錯誤:不能隱式轉換
double d2 = static_cast<double>(m); // 正確:顯式轉換

2.2 顯示類型轉換

2.2.1 static_cast

靜態轉換:最常用的顯式轉換,用于在編譯期進行有明確關聯的安全轉換。

場景:

  • 基本數據類型之間的轉換

  • void 指針與具體類型指針之間的轉換

  • 類層次結構中的上行轉換(派生類→基類)

int i = 10;
double d = static_cast<double>(i); // int -> doublevoid* voidPtr = &i;
int* intPtr = static_cast<int*>(voidPtr); // void* -> int*
2.2.2 reinterpret_cast

reinterpret_cast?用于在兩種不相關類型之間進行轉換,其本質是對原始數據的底層位模式進行重新解釋,也就是說轉換后對原有內存的訪問解釋已經完全改變了。

場景:

  • 任意指針類型之間的轉換

  • 指針和整數之間的轉換

int i = 0x12345678;
char* p1 = reinterpret_cast<char*>(a);
2.2.3 const_cast

const_cast?于const類型到?const類型的轉換,去掉了const屬性。

void oldFunction(char* str) {cout << str << endl;
}const char* message = "Hello";// oldFunction(message); // 錯誤:不能將 const char* 轉換為 char*
oldFunction(const_cast<char*>(message)); // 正確// 危險示例!
const int ci = 10;
int* badPtr = const_cast<int*>(&ci);
*badPtr = 20; // 未定義行為!
2.2.4 dynamic_cast
  • dynamic_cast?于將基類的指針或者引?安全的轉換成派?類的指針或者引?。如果基類的指針或者引?時指向派?類對象的,則轉換回派?類指針或者引?時可以成功的,如果基類的指針指向基類對象,則轉換失敗返回nullptr,如果基類引?指向基類對象,則轉換失敗,拋出bad_cast異常。

  • 其次dynamic_cast要求基類必須是多態類型,也就是基類中必須有虛函數。因為dynamic_cast是運?時通過虛表中存儲的type_info判斷基類指針指向的是基類對象還是派?類對象。

場景:

  • 安全的下行轉換(基類→派生類)

要求:

  • 基類必須有虛函數(多態類型)
class Base { virtual void foo() {} };
class Derived : public Base {};Base* basePtr1 = new Derived(); // 實際指向 Derived
Base* basePtr2 = new Base();    // 實際指向 Base// 安全的下行轉換
Derived* d1 = dynamic_cast<Derived*>(basePtr1); // 成功
Derived* d2 = dynamic_cast<Derived*>(basePtr2); // 失敗,返回 nullptrif (d2) {// 安全操作
} else {cout << "轉換失敗!" << endl;
}// 引用轉換(失敗會拋出異常)
try {Derived& rd = dynamic_cast<Derived&>(*basePtr2);
} catch (const std::bad_cast& e) {cout << "引用轉換失敗" << endl;
}
  • dynamic_cast?的實現基礎是?RTTI(運行時類型信息)。編譯器會為每個包含虛函數的類生成額外的類型信息,這些信息在程序運行時可用。

  • 什么是RTTI?

    • RTTI?是 C++ 提供的一種機制,允許程序在運行時獲取和操作對象的類型信息。它讓程序能夠動態地確定對象的實際類型,即使是通過基類指針或引用來操作對象。

    • typeid運算符:用于獲取對象的類型信息,返回一個?std::type_info?對象的引用。

    • dynamic_cast:用于在繼承層次中進行安全的類型轉換,依賴于 RTTI 信息。

注意:C/C++都不是類型安全的語言。

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

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

相關文章

【Java】Windows切換Java8和Java11

現在有些項目要升級到Java17, 所以需要切換不同的java版本。 如何安裝Java8 由于已經安裝了jJava8, 之前的安裝文章&#xff1a;【Java】jdk8安裝——英文版 如何安裝Java17 Java17下載地址 https://www.oracle.com/java/technologies/downloads/#java17-windows 下載到電…

SQLite 數據庫核心知識與 C 語言編程

一、數據庫基礎概念1.1 數據庫分類根據規模和應用場景&#xff0c;數據庫可分為以下幾類&#xff1a;大型數據庫&#xff1a;Oracle&#xff08;適用于企業級高并發、大容量場景&#xff09;中型數據庫&#xff1a;MySQL、MSSQL&#xff08;適用于中小型系統、Web 應用&#xf…

Netty 調優篇:實戰配置、性能監控與常見坑

&#x1f680; Netty 調優篇&#xff1a;實戰配置、性能監控與常見坑前面我們已經深入了 Netty 的 線程模型、Pipeline、EventLoop、內存池、零拷貝和背壓機制。 但在實際工作中&#xff0c;很多人踩坑的地方不是“源碼沒看懂”&#xff0c;而是 調優沒做好。 今天我們就從三個…

Linux Node.js 安裝及環境配置詳細教程

如果您喜歡此文章&#xff0c;請收藏、點贊、評論&#xff0c;謝謝&#xff0c;祝您快樂每一天。 一、Node.js是什么 Node.js是一個基于Chrome V8引擎的[JavaScript運行環境]。 Node.js使用了一個事件驅動、非阻塞式I/O 的模型。 Node.js是一個讓JavaScript運行在服務端的開…

呼叫中心系統IVR流程設計的心理學

呼叫中心的 IVR&#xff08;交互式語音應答&#xff09;系統看似是 “機器與用戶的對話”&#xff0c;實則暗藏對用戶心理的精準把握。其設計需圍繞降低焦慮、提升效率、強化信任三大核心目標&#xff0c;背后依托認知心理學、行為心理學、情感心理學等理論支撐。一、認知負荷理…

一些開源或免費的網絡管理工具

整理開源及免費網絡管理工具推薦,涵蓋監控、配置、安全、流量分析等場景,適用于不同規模的網絡環境: ?一、網絡監控與性能分析? 1. ?Zabbix? ?特點?:企業級監控方案,支持SNMP、IPMI、JMX等多種協議,提供實時儀表盤、告警通知和自動化發現功能。 ?適用場景?:服…

谷粒商城項目-P16快速開發-人人開源搭建后臺管理系統

1.對腳手架工程進行改造 此項目選用的腳手架工程是人人開源 地址&#xff1a;人人開源 選擇的是下圖標紅的renren-fast作為后端&#xff0c;renren-fast-vue作為前端 克隆上述兩個項目 2.后端改造 2.1將renrenfast項目的git文件夾刪除后&#xff0c;拖進后端代碼文件夾中 2…

V少JS基礎班之第八彈:this

文章目錄一、 前言二、本節涉及知識點三、重點內容1、從新的角度認識this2、this是函數的參數3、this的值4、函數的調用1- 裸函數調用2- 函數作為構造函數調用3- 函數作為對象的方法調用4- 函數顯示調用5- 箭頭函數一、 前言 第八彈內容是this。this相對來說難度不大&#xff…

《堆的詳解:結構、操作及堆排序算法》

目錄 一.堆的概念與結構 1.1 堆的概念 1.2 堆性質&#xff1a; 1.3 堆的結構定義 二.堆的初始化和銷毀 2.1 堆的初始化&#xff1a; 2.2 堆的銷毀&#xff1a; 三.堆的插入數據(含向上調整算法的實現) 3.1 插入邏輯 3.2 插入函數 3.3 向上調整算法 三. 堆的刪除數…

深入解析 Kubernetes 中的 Service 資源:為應用提供穩定的網絡訪問

什么是 Kubernetes 中的 Service&#xff1f; 在現代微服務架構中&#xff0c;服務之間的通信和負載均衡是至關重要的。尤其是在 Kubernetes 環境中&#xff0c;由于 Pod 是動態創建和銷毀的&#xff0c;如何為一組 Pod 提供穩定的訪問入口&#xff0c;成為了架構設計中的一個關…

使用Samba網絡磁盤作為MacOS時間機器的遠程備份磁盤

最近考慮MacOS系統升級&#xff0c;所以需要做磁盤備份&#xff0c;MacOS里有個備份磁盤很方便的工具&#xff1a;時間機器&#xff0c;可以自動定期備份磁盤&#xff0c;但是一般需要一個大點的移動硬盤插在macbook上選擇其為備份磁盤&#xff0c;可惜我并沒有移動硬盤&#x…

智能頭盔實時監控系統設計與實現

智能頭盔實時監控系統設計與實現 源碼 https://gitee.com/intostars/csdn-demo/tree/master/src/views/smartHelmet 預覽 一、功能概述 智能頭盔實時監控系統是基于Vue 3和TypeScript開發的一套用于遠程監控和控制智能頭盔設備的前端應用模塊。該系統通過WebSocket與后端服務…

Docker 學習筆記(八):容器運行時工具實踐及 OpenStack 部署基礎

容器管理工具Containerd nerdctl 實踐 nerdctl管理存儲 nerdctl命令創建容器的時候&#xff0c;可以使用-v選項將本地目錄掛載給容器實現數據持久化 示例&#xff1a; [rootlocalhost ~]# mkdir /data [rootlocalhost ~]# nerdctl run -d -v /data:/data busybox -- sleep infi…

Unity鍵盤控制角色運動

以下是一個完整的Unity角色移動和跳躍腳本,支持WASD或方向鍵移動: 使用說明 確保組件設置正確: 確保您的游戲對象有一個CharacterController組件 如果沒有,可以通過菜單 "Component -> Physics -> Character Controller" 添加 相機設置: 確保場景中有一…

linux 宏 DEVICE_ATTR

理解 DEVICE_ATTR DEVICE_ATTR 是 Linux 內核中用于創建設備屬性的宏&#xff0c;通常用于 sysfs 文件系統。通過 sysfs&#xff0c;用戶空間的程序可以讀取或修改內核中的設備屬性。DEVICE_ATTR 宏定義在 <linux/device.h> 頭文件中&#xff0c;用于聲明和定義一個設備屬…

MCP模型上下文協議以及交互流程

1. MCP 是什么全稱&#xff1a;Model Context Protocol定位&#xff1a;讓大語言模型&#xff08;LLM&#xff09;能在“上下文”之外&#xff0c;按統一格式訪問外部數據、調用插件、持久化狀態。動機&#xff1a;以前每家框架&#xff08;LangChain、LlamaIndex 等&#xff0…

MySQLTransactionRollbackException

問題描述mysql部署1主3從&#xff0c;昨天發現主庫有大量報警錯誤&#xff1a;Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction ; Deadlock found when trying to get lock; …

Redis環境搭建指南:Windows/Linux/Docker多場景安裝與配置

Redis環境搭建指南&#xff1a;Windows/Linux/Docker多場景安裝與配置 1. Redis安裝方式概覽 1.1 安裝方式對比 安裝方式適用場景優點缺點難度Windows直接安裝開發調試安裝簡單&#xff0c;Windows兼容好性能不如Linux&#xff0c;生產不推薦?Linux源碼編譯生產環境性能最佳…

leetcode.80刪除有序數組中的重復項2

題目描述 給你一個有序數組 nums &#xff0c;請你 原地 刪除重復出現的元素&#xff0c;使得出現次數超過兩次的元素只出現兩次 &#xff0c;返回刪除后數組的新長度。 不要使用額外的數組空間&#xff0c;你必須在 原地 修改輸入數組 并在使用 O(1) 額外空間的條件下完成。…

運動卡新手入門及常見問題處理

1.新手入門1.1 插卡打開包裝&#xff0c;拿出PCI板卡&#xff0c;如下圖&#xff1a;打開電腦機箱蓋&#xff0c;找到PCI插槽&#xff0c;如下圖&#xff08;紅色框部分是PCI槽&#xff0c;有些主板上PCI槽是白色或其他顏色&#xff09;&#xff1a;插入板卡&#xff0c;如下圖…