[英]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 ++聲明讀取的一般規則:如果您將聲明作為表達式鍵入,您將獲得其類型。
*AnimalCreation
這意味着AnimalCreation
是一個指針 (*AnimalCreation)()
這意味着*AnimalCreation
是一個不帶參數的函數,因此AnimalCreation
是一個不帶參數的函數的指針 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.