2016-11-10 207 views
1

想象一下,我有一個Base類和兩個派生自它的類One和Two。在Java中,我可以有以下情形:在C++中實例化派生類型

Base b; 
if(condition) 
    b = new One(); 
else 
    b = new Two(); 

在對象類型在運行時確定(上述目的去堆)。我希望能夠在運行時實例化對象類型 - 我所知道的是它們都共享相同的Base類型 - 但我想保留它的堆棧分配,如下所示:

Base b; 

這樣做的最好方法是什麼?

+1

刪除記憶 - 有沒有(Java不分配堆棧上的對象,所以這2例是不相同)。即使你可以,你的對象也會被[切片](http://stackoverflow.com/questions/274626/what-is-object-slicing)爲「Base」類型。 –

+1

你不能(以任何通知可維護的方式)。它是堆棧分配的,所以它的大小必須在分配時已知。記住在Java中你的對象不是堆棧分配的,所以雖然用C++編寫的Java代碼暗含了堆棧分配,但並不意味着在Java中。 – djgandy

+0

這是經典的XY問題 - http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Slava

回答

1

這樣做的最好方法是什麼?

你不行。如果你聲明一個變量類型爲Base,那麼它的堆棧分配將適用於持有Base的實例,但不適用於派生類型的實例(它可能較大,儘管不是,但仍不能完成你的任務問; C++中的變量的運行時類型始終與其聲明的類型相同)。充其量,您可以將slice派生實例轉換爲Base-類型的變量。

最好的選擇是使用一個指針,可選地包裝在shared_ptrunique_ptr中給你類似的語義。假定所有權沒有被轉移時,該對象在超出範圍時自動銷燬)。

Base* b = (condition) ? (Base *) new One() : new Two(); 
auto bptr = shared_ptr<Base>(b); 

注意,這是什麼讓你實際上是一樣的Java。對象本身是堆分配的,但是對它的引用是堆棧分配的。儘管有語法,但引用類型的Java變量本質上等同於C++中的指針。

-1

爲了在C++中使用繼承,您需要定義一個指針而不是靜態對象,然後使用new關鍵字對其進行實例化。

實施例:

Base* b; 
if(condition) 
    b = new One(); 
else 
    b = new Two(); 
0

採取的,例如:

Derived d; 
Base* b = &d; 

d是堆棧(自動存儲器)上,但仍然多態性將在b工作。

如果您沒有基類指針或對派生類的引用,則多態性不起作用,因爲您不再具有派生類。就拿

Base c = Derived(); 

c對象不是Derived,但Base,因爲切片。因此,從技術上講,多態性仍然有效,只不過你不再有一個對象來談論。

現在採取

Base* c = new Derived(); 

c只是指向內存的某個地方,你真的不關心這是否是實際上是一個BaseDerived,但調用的virtual方法將被動態解析。

所以,看起來,與Java不同,沒有堆分配或指針方式,沒有辦法實現動態綁定。

0

正如評論說你不能。嗯,你可以但不會運行:

Base &b = *(condition ? (Base *)&One() : (Base *)&Two()); // BROKEN CODE DO NOT USE 

(構建使用-fpermissive,但不這樣做!)

因爲One & Two對象是臨時對象。 b一旦你通過下一行就會無效=>不這樣做(不知道我已經說過了)

以下工作,但不完美:在堆棧上構建兩個對象,所以只有在你可以負擔得起。根據條件只要選擇:

One one; 
Two two; 
Base &b = *(condition ? (Base *)&one : (Base *)&two); 

爲了避免雙重分配,我能想到的在使用方面最接近的事是採取分配的對象的引用(還沒有自動變量,不好意思):

Base &b = *(condition ? (Base *)new One() : (Base *)new Two()); 

因此,您可以在代碼中使用b作爲Base

你還有如果你想成爲堆棧中分配你的對象與

delete (&b); 
+0

對不起,我沒有測試過的唯一代碼:)修復。 –