簡體   English   中英

關於void指針,類和轉換

[英]about void pointer, classes and casting

我有大約一年或兩年的c ++經驗,但我的編碼方式與我在Java中編碼的方式相同(簡單的oop東西)。 現在我有這個我不明白的示例代碼。 (它很大,所以我試着縮短它,我希望它對你們來說足夠清楚了)

//in .h file
typedef void*(*AnimalCreation)();

//in .cpp
void foo(void* p)
{
    AnimalCreation ac = (AnimalCreation)p;

    Animal* current_animal = reinterpret_cast<Animal*>(ac());
    current_animal->init();
}

//somewhere in another class foo is called
Dog* dog = new Dog(); //Dog is a subclass of Animal
foo((void*)&dog) 

AnimalCreation的目的是什么? 那和之間的區別是什么?

typedef void(*AnimalCreation)();`//without asterisk after void

foo里面發生了什么?

如果foo接收到的期望參數始終是Animal的子類,為什么程序員需要像上面那樣實現它而不僅僅是foo(Animal *)?

謝謝。

typedef void(*AnimalCreation)();

這聲明“AnimalCreation”用作指向函數的類型別名,該函數不返回任何值,而這

typedef void*(*AnimalCreation)();

聲明它被用作指向函數的指針的類型別名,該函數返回一個void指針,即一個你不知道它的類型的地址。

foo里面,你會收到這樣一個“通用地址”,並且你是C-casting (可能不安全,在運行時檢查)它是一個函數指針。 這將由您自己承擔風險:您不知道收到的地址指向的是什么。 之后,您將調用該函數並接收另一個void指針,您將其重新解釋為(危險) Animal對象。 然后你用它。

函數指針不能是任何東西的子類,所以我不認為該代碼中的參數是Animal子類...而是Animal類的子類是該函數返回的對象 假設它也是一個多態類,那么您將能夠使用虛擬繼承規則調用其方法。 如果您打算檢查函數調用接收的指針,並且您不確定它是否是Animal類的子類,那么您寧願使用dynamic_cast

作為旁注:在函數指針和void *之間進行轉換在C ++中是一種不好的做法 ,因為您丟失了有價值的類型信息。

typedef行是AnimalCreation,被定義為函數指針類型

函數foo接受一個void *參數,它將其轉換為AnimalCreation類型(即進入函數指針類型)。 然后它可以通過函數指針調用該函數。 此調用返回void *(根據typedef - 在firts括號之前的部分是返回類型,因此為void *),然后通過reinterpret_cast將其轉換為Animal *。

如果你從typdef中刪除了星號 - 它仍然會聲明一個函數指針類型,但現在返回值將是void而不是void *(即沒有返回,而不是指針)。 您仍然可以通過函數指針調用該函數,但它不會返回任何內容。

總而言之,這是一個不錯的小函數指針教程。

編輯:這個代碼似乎正在做的大局 - 這是在C ++中實現'工廠模式'的一種方式 - 抽象對象的創建,並將多態基類指針返回到派生類。 在void *和函數指針之間進行轉換和reinterpret_cast不是實現這一目標的最好方法,對於你可以在這里查看的替代方法

首先,這是非常丑陋的C風格代碼。

typedef void*(*AnimalCreation)();

要解釋這一點,請遵循C&C ++聲明讀取的一般規則:如果您將聲明作為表達式鍵入,您將獲得其類型。

  1. *AnimalCreation這意味着AnimalCreation是一個指針
  2. (*AnimalCreation)()這意味着*AnimalCreation是一個不帶參數的函數,因此AnimalCreation是一個不帶參數的函數的指針
  3. void *(*AnimalCreation)()這意味着(*AnimalCreation)()是一個void* (=指向void指針),因此AnimalCreation是一個指向函數的指針,該函數不帶參數並返回void*

如果它只是typedef void (*AnimalCreation)(); ,它將是一個指向函數的指針,該函數不帶參數並且不返回任何值(即返回void )。

現在, foo()

這需要一個void* (指向任何東西的指針)並將其解釋為AnimalCreation - 作為一個指向函數的指針,該函數不帶參數並返回void* 如果傳遞給foo的參數實際上是那種類型,那么一切都很好。 如果傳入其他內容,程序將顯示未定義的行為,這意味着任何事情都可能發生。 它很可能會崩潰,因為它可能試圖將數據解釋為代碼。

foo()調用傳入的函數,返回void* foo()然后將其解釋為指向Animal的指針。 如果那是函數實際返回的,那很好。 如果不是,則再次定義未定義的行為。

最后,您正在顯示的調用將強制發生未定義行為,因為它正在傳遞指向對象的指針的地址。 但是,如上所述, foo()會將其解釋為函數的地址,並嘗試調用該函數。 隨之而來的是歡鬧。

總而言之,這樣的代碼很糟糕,作者應該感覺很糟糕。 您期望看到這樣的代碼的唯一地方是與C風格的外部庫的互操作性,在這種情況下,它應該被非常好地記錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM