2017-04-18 45 views
2

的存儲的子類指針所以說我有一個名爲Libitem一個父類,並呼籲Book子類。如果我在Libitem的指針地圖內存儲了一個Book的指針,當我嘗試再次訪問它時,是否會返回指針Book?就像這樣:在地圖父類的指針

std::map<int, Libitem*> catalog; 
Libitem* b = new Book(); 
catalog[1] = b; 
Libitem* old_book = catalog[1]; //would old_book be a Book or a Libitem? In other word would it 
           //have all the function of a Book class? 
+0

請搜索並閱讀關於* downcasting *。 –

回答

2

你檢索你的對象是這樣的:

Libitem* old_book = catalog[1]; 

就這樣,編譯器只知道你有一個名爲類型的old_book指針Libitem變量。如果你自己單獨閱讀特定行,你會注意到,唯一的這是你和編譯器當時唯一的信息。當你自己讀這行的時候就是編譯時間。通過閱讀代碼你可以知道什麼。

當程序實際運行,該變量可以指向Book類型的對象。但是這隻在程序運行時才知道,因此,運行時間

名稱查找發生在C++編譯時。當你調用一個函數的對象上是這樣的:

// Type of an_object is a_struct 
a_struct an_object; 

an_object.member_function(); 

編譯器將着眼於可用的功能裏面a_struct。由於編譯器正在聲明結構體中的名稱,所以在編譯時真正解析了名稱。


讓我們回到你的案例。你有一個指向Libitem的指針。如果您嘗試使用箭頭來訪問它裏面的東西:

old_book->something 

要解決什麼something是,編譯器會往裏Libitem它,因爲old_book類型是一個指向Libitem。即使指針指向一個子類的實例,唯一的編譯器知道肯定是對象的實際類型指出,至少Libitem。現在

,你的人知道比編譯器的更多。你知道指針old_book指向類Book的一個實例。您想訪問Book的會員。

爲此,您必須明確告訴編譯器您想使用來自子類的成員。要做到這一點,你的變量必須是Book的類型,所以編譯器會查找適當的類。爲此,您可以將您的變量轉換爲另一種類型。由於您將變量轉換爲層次結構中較低級別的變量,因此將其稱爲向下傾斜。那種鑄鐵的,我們可以在這種情況下使用是dynamic_cast,一個演員,其中將着眼於運行的是由指針所指向的實際類型的實例:

if (Book* the_old_book = dynamic_cast<Book*>(old_book)) { 
    // We can use the_old_book here, which his type is Book! 
} else { 
    // The cast failed, the real for of the variable is not Book, 
    // and the_old_book points to nullptr 
} 

正如你所看到的,我們創建了一個新的指針名爲the_old_book,它由演員的結果初始化。如果old_book指向的實例的實際類型實際上不是Book,則該投射將失敗並返回nullptr。由於這發生在運行時,我們必須使用運行時分支驗證我們的新變量,if。如果轉換失敗,則執行的塊將爲else塊。

+0

好吧,整個轉換機制將會非常有幫助......但只是爲了確保存儲在'catalog [1]'中的指針始終是一個技術上的孩子對嗎?換句話說,如果我將存儲在'catalog [1]'中的指針傳遞給另一個向量或映射,我是否能夠從新集合中檢索它並仍然可以動態地將其轉換爲'Book'? –

+0

是的。實際實例的類型不會改變。您可以創建,複製和轉換指針。如果最終指針指向您分配對象的同一位置,則可以向下轉發它。 –

2

這就像任何其他晶指針:一個Libitem的功能,但在方法Book的任何虛擬覆蓋。

但是:你將無法訪問的Book非虛方法,無論是具有完全不同的名稱,任何方法的功能/法Libitem,同名但不同參數簽名的方法Libitem,或非虛擬Libitem中的方法具有相同名稱和簽名的情況。

當然,如果你是一個強硬樣的人,你可以向下轉換(由@SomeProgrammerDude指出)。

+0

等等,這樣只能訪問一本書的虛擬覆蓋?所有不是虛擬的,而是「Book」(而不是從'Libitem'繼承)的一部分將不可訪問? –

+0

任何不是從'Libitem'繼承的東西都是不可訪問的 –