C 轉型動作的新認識

2021-08-09 06:12:53 字數 2623 閱讀 3489

之前學習c/c++的時候一直都認為型別轉換(不管是顯式的還是隱式的)其實什麼都沒有做,只是告訴編譯器型別改變了一下,讓它的翻譯記憶體二進位制資料的時候以新型別的套路去翻譯而已。

然而當我看到effective c++ rule 27.關於轉型動作會觸發其它動作時,我是很驚訝的。

先貼出一段**來看看,轉型並不是什麼都沒有做,相反,它做了很多事情,我們一一來看。

#include 

#include

class super1

super1(const super1& rhs)

virtual ~super1()

virtual

void display()

void hello()

};class super2

void display()

};class derived:

public super1,public super2

};int main()

**不複雜,有兩個基類:super1和super2.

有乙個繼承類:derived ,多繼承自super1和super2.

main函式內部,也就是簡單的取位址,並將子類的位址轉換為基類位址。

猜猜會列印出來什麼呢?

如果是在以前,我肯定會認為 sp1,sp2,child這三個值是一樣的。

然而:

輸出為:

6ffd58 6ffd60 6ffd58
sp2 比sp1向高位址偏移了8個位元組(super1 內部有乙個4個位元組的num,還有乙個4位元組的vtable指標,因為類裡面有虛函式)。而child與sp1相同的。

這不禁讓我去思考,轉型cast 是什麼東西?它究竟是如何實現的?

轉型可以分為兩大類:物件轉型和指標轉型(包括引用轉型)

物件轉型的行為看起來就類似於呼叫類的建構函式來生成物件。如果發現沒有適當的建構函式用來呼叫,那麼就會轉型失敗。

例如還是上面的**:

#include 

#include

class super1

super1(const super1& rhs)

virtual ~super1()

virtual

void display()

void hello()

};class super2

void display()

};class derived:

public super1,public super2

};int main()

在子類的display函式內部:

我們企圖去呼叫父類 super1的函式display.

但是我們卻寫出了:(super1 (*this)).display()這樣的**。

我們看到 super1(*this) 這個呼叫形式是不是就剛好匹配了複製建構函式super1(const super1& )?沒錯!上面這個過程,實際上會先用*this的內容生成乙個super1 類的匿名例項,然後再呼叫這個匿名例項的display()方法。

我們看看輸出:

call super1(const super1 & rhs).

here is super1, the num is

1 (50fb28)

call ~super1()

here is

derived

class, the num is num1 1(50fd10) and num2 -858993460(50fd18) .

50fd0c 50fd14 50fd0c

可以看到 前三行都是那個super1類的匿名物件,這個物件與子類child內部的super1是不同的!

這可能與我們想要的有些出入,因為我們寫出(super1 (*this)).display() 是想父類的display指標能夠展示當前物件this的num1的內容,而不是想要去重新生成乙個super1物件。這個情況還不算特殊,因為這只是在讀取num1的內容。

更特殊的是 display的內部邏輯可能會修改num1的值,那麼這種呼叫方式下父類display函式對num1的修改 實際上是不會影響到this物件的num1的值的。因為它們本來就存在不同的記憶體區域。

實際上,我們想實現的是:

virtual void display()

這種效果,這種實現方式下,display都是對當前this物件的num1進行讀取。

同樣的:

int num=1

double num2=(double)num/3;

其實內部的執行過程是:生成乙個匿名double,並用num的值去初始化這個匿名物件,然後這個匿名物件在參與運算。

那麼指標間的轉型又是怎麼完成的呢?

個人猜測過程也是類似的,也是呼叫某類指標的複製建構函式去生成乙個匿名指標物件,但是這種建構函式不是由程式設計師編寫的,而是由編譯器自動生成的,程式設計師無法控制,而且不同的編譯器還會有不同的操作。此類建構函式在內部實現中很可能會根據引數的不同,做一些指標的偏移、變換操作,尤其是使用多重繼承的時候。

(2 2)訊號的概念,認識,處理動作

程序之間的常用通訊手段 傳送訊號,kill 第二章第二節講過 上節課討論過 sighup 訊號 通知 事情通知 用來通知某個程序發生了某乙個事情 事情,訊號都是突發事件,訊號是非同步發生的,訊號也被稱呼為 軟體中斷 訊號如何產生 a 某個程序傳送給另外乙個程序或者傳送給自己 b 由核心 作業系統 傳...

3 3 訊號的概念 認識 處理動作

程序之間的常用通訊手段 傳送訊號,kill 第二章第二節講過 上節討論過 sighup 訊號 通知 事情通知 用來通知某個程序發生了某乙個事情 事情,訊號都是突發事件,訊號是非同步發生的,訊號也被稱呼為 軟體中斷 訊號如何產生 a 某個程序傳送給另外乙個程序或者傳送給自己 b 由核心 作業系統 傳送...

const的新認識

今天發現乙個有趣的現象,有如下 void fun char p int main void fun char p 和c d這兩行會出現waring 其實這兩行都是相同的賦值語句,都是有const修飾的賦值給沒有const修飾的。也就是說只能把沒有const修飾的賦值給有const修飾的,反之則war...