詳解C++?轉(zhuǎn)換的非正式分類
C++ 正式分類方法是直接按語法分類,分為:隱式轉(zhuǎn)換和顯示轉(zhuǎn)換。隱式轉(zhuǎn)換又稱為標(biāo)準(zhǔn)轉(zhuǎn)換。顯示轉(zhuǎn)換又分為:C 風(fēng)格轉(zhuǎn)換、函數(shù)風(fēng)格轉(zhuǎn)換、C++ 風(fēng)格轉(zhuǎn)換。C++風(fēng)格轉(zhuǎn)換就是 static_cast
、dynamic_cast
、const_cast
和 reinterpret_cast
這 4 種。
有很長一段時(shí)間我都有這樣的疑問:轉(zhuǎn)換前的對(duì)象和轉(zhuǎn)換后的對(duì)象是不是同一個(gè)?
現(xiàn)在,我引入一種非正式分類方法,分為:同對(duì)象轉(zhuǎn)換和異對(duì)象轉(zhuǎn)換。這兩個(gè)術(shù)語是我自己編的,只是為了方便說明問題。
- 同對(duì)象轉(zhuǎn)換:轉(zhuǎn)換后的對(duì)象和轉(zhuǎn)換前的對(duì)象是同一個(gè),也就是不會(huì)構(gòu)造一個(gè)新的對(duì)象,還是使用原來的對(duì)象。
- 異對(duì)象轉(zhuǎn)換:轉(zhuǎn)換后的對(duì)象和轉(zhuǎn)換前的對(duì)象不是同一個(gè),也就是會(huì)構(gòu)造一個(gè)新的的對(duì)象。
下面分別說明這兩種轉(zhuǎn)換的典型情況。
一、同對(duì)象轉(zhuǎn)換
所有的值類別轉(zhuǎn)換及其變形都是同對(duì)象轉(zhuǎn)換。
1. 值類別轉(zhuǎn)換
C++ 的值類別可以使用 static_cast
進(jìn)行轉(zhuǎn)換,屬于同對(duì)象轉(zhuǎn)換。注意:static_cast<T&>()
和 static_cast<T&&>()
的語義不是將一個(gè)對(duì)象轉(zhuǎn)換為一個(gè)引用,而是轉(zhuǎn)換對(duì)象的值類別,使其能被對(duì)應(yīng)的引用綁定。
// 左值轉(zhuǎn)換為左值 int a = 1; static_cast<int&>(a) = 2; std::cout << a << std::endl; // 輸出:2
// 左值轉(zhuǎn)換為右值 int a = 1; int&& b = static_cast<int&&>(a); b = 2; std::cout << a << std::endl; // 輸出:2
// 右值轉(zhuǎn)換為右值,轉(zhuǎn)換前對(duì)象為非字面量 int a = 1; int&& b = static_cast<int&&>(static_cast<int&&>(a)); b = 2; std::cout << a << std::endl; // 輸出:2
2. 借助值類別轉(zhuǎn)換進(jìn)行 OOP 轉(zhuǎn)換
這種情況帶有值類別轉(zhuǎn)換,屬于同對(duì)象轉(zhuǎn)換。
// upcast struct A { int x = 1; }; struct B : A { }; B b; static_cast<A&>(b).x = 2; std::cout << b.x << std::endl; // 輸出:2
// downcast struct A { int x = 1; }; struct B : A { }; B b; static_cast<B&>(static_cast<A&>(b)).x = 2; std::cout << b.x << std::endl; // 輸出:2
// sidecast struct A1 { virtual void f1() {} int x = 1; }; struct A2 { virtual void f2() {} int y = 1; }; struct B : A1, A2 { }; B b; dynamic_cast<A2&>(static_cast<A1&>(b)).y = 2; std::cout << b.y << std::endl; // 輸出:2
2. 借助值類別轉(zhuǎn)換進(jìn)行 const_cast
轉(zhuǎn)換
這種情況帶有值類別轉(zhuǎn)換,也是同對(duì)象轉(zhuǎn)換。注意:通過 const_cast
修改原本為 const
的對(duì)象是未定義行為。
struct A { int x = 1; }; { int a; const_cast<int&>(const_cast<const int&>(a)) = 2; std::cout << a << std::endl; } { A a; const_cast<A&>(const_cast<const A&>(a)).x = 2; std::cout << a.x << std::endl; } /* 輸出: 2 2 */
二、異對(duì)象轉(zhuǎn)換
所有的非值類別轉(zhuǎn)換都是異對(duì)象轉(zhuǎn)換。
1. 普通的類型轉(zhuǎn)換
// 標(biāo)量類型 int a = 1; int&& b = static_cast<int>(a); b = 2; std::cout << a << std::endl; // 輸出:1
// 類類型 struct A { A() { std::cout << "A::A() " << x << std::endl; } A(const A&) { std::cout << "A::A(const A&) " << x << std::endl; } ~A() { std::cout << "A::~A() " << x << std::endl; } int x = 1; }; A a; A&& b = static_cast<A>(a); b.x = 2; std::cout << b.x << std::endl; /* 輸出: A::A() 1 A::A(const A&) 1 2 A::~A() 2 A::~A() 1 */
2. 指針轉(zhuǎn)換
轉(zhuǎn)換之后,指針本身是異對(duì)象,指針?biāo)傅膶?duì)象是同對(duì)象。這種情況也包含:借助指針進(jìn)行 OOP 轉(zhuǎn)換,借助指針進(jìn)行 const_cast
轉(zhuǎn)換。
int* a = new int; std::cout << a << std::endl; int* && r = static_cast<int*>(a); r = nullptr; std::cout << a << std::endl; /* 輸出: 0x1ffdeb0 0x1ffdeb0 */
到此這篇關(guān)于C++ 轉(zhuǎn)換的非正式分類的文章就介紹到這了,更多相關(guān)C++ 轉(zhuǎn)換非正式分類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ for循環(huán)與nullptr的小知識(shí)點(diǎn)分享
這篇文章主要是來和大家介紹一些C++中的小知識(shí)點(diǎn),本文分享的是for循環(huán)與nullptr,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-05-05C/C++代碼操作MySQL數(shù)據(jù)庫詳細(xì)步驟
這篇文章主要給大家介紹了關(guān)于C/C++代碼操作MySQL數(shù)據(jù)庫的相關(guān)資料,通過文中的這些示例,我們可以連接到MySQL數(shù)據(jù)庫,并執(zhí)行常見的數(shù)據(jù)庫操作,如創(chuàng)建表、插入數(shù)據(jù)和查詢數(shù)據(jù),需要的朋友可以參考下2023-12-12c++ 完備的運(yùn)行時(shí)類型信息(動(dòng)態(tài)類型信息)
這篇文章主要介紹了c++ 完備的運(yùn)行時(shí)類型信息,需要的朋友可以參考下2017-07-07基于Qt實(shí)現(xiàn)可拖動(dòng)自定義控件
這篇文章主要為大家詳細(xì)介紹了如何基于Qt實(shí)現(xiàn)可拖動(dòng)自定義控件,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-04-04C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡單實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡單實(shí)例的相關(guān)資料,希望通過本文能幫助大家實(shí)現(xiàn)優(yōu)先隊(duì)列,需要的朋友可以參考下2017-08-08