2011-10-09 60 views
3

在代碼中有一些特殊的類,並且有一些正常的類。我想區分它們,因爲需要給予不同的待遇。所有這些特殊類基地(不是任何其他類的孩子)額外的繼承對對象結構或實例化有什麼影響嗎?

爲了實現這個目標,我令牌化在源代碼中特殊class ES通過和空struct將繼承對他們說:

struct _special {}; // empty class 
class A : public _special { // A becomes special 
... 
}; 
class B { // 'B' remains normal 
... 
}; 
class D : public A { // 'D' becomes special due to 'A' 
... 
}; 

每當需要,我可以找到使用is_base_of<Base,Derived>分離特殊和普通類。替代的方法是一直使用typedef特殊類中的:

class A { 
    public: typedef something _special; 
}; 

的問題是,如果A的孩子是從多個類繼承,然後會有曖昧typedef秒。

問題:添加這種接口如繼承與空class _special,將它它傷害以任何方式的當前代碼(例如對象的結構化,編譯錯誤等)?

回答

0

不知道你的意思與傷害對象結構(注意詳細點嗎?),但應該沒有編譯器錯誤,實例化/構造的歸類從_special派生不會改變,因爲_special有一個默認構造函數和性能方面,編譯器可能會應用空基類優化。這就是說,使用typedefs來標記類的選項可能是一個更好,更清晰和更可擴展的解決方案。就像A的孩子繼承多個其他類一樣,它們都可能從_special繼承。

3

大多數(如果不是所有的)體面編譯器對簡單情況都實現空基優化(EBO),這意味着您的對象大小不會通過從空基繼承而增長。然而,當一個類以不止一種方式從空的基地繼承時,由於需要針對相同類型的不同空白基地具有不同的地址,優化可能是不可能的。爲了防止這種情況發生,通常會將空白基底作爲將派生類作爲參數的模板,但這會使is_base_of不可用。

就我個人而言,我會在外部實現這種分類。模板專門化不會得到類間接被認爲特殊的派生類的期望結果。它看起來像你正在使用C++ 11所以我會做:

std::false_type is_special(...); 
std::true_type is_special(A const*); 

而且隨着decltype(is_special(static_cast<T*>(0)))取代is_base_of<T, _special>。在C由具有分類函數的返回類型不同尺寸的++ 03同樣可以與sizeof特技來實現:

typedef char no_type; 
struct yes_type { no_type _[2]; }; 

no_type is_special(...); 
yes_type is_special(A const*); 

並與sizeof(is_special(static_cast<T*>(0))) == sizeof(yes_type)替換is_base_of<T, _special>。您可以在輔助類模板中包裝分類檢查。

+0

很好的回答,但我沒有使用C++ 11。 – iammilind

+0

@iammilind:你仍然可以使用類型特徵:) –

+0

@iammilind:C++ 03解決方案現在包括在內。 –

3

內存中對象的佈局只在C++標準中部分指定,但是大多數編譯器都使用某些約定。空類型會佔用一點內存(所以它們將有一個內存地址,這會給它們的指針標識)。這些額外的內存通常只有四個字節,在大多數情況下不需要擔心。如果您從另一方面的空類型繼承,它不應該增加對象的大小,因爲對象的其餘部分將佔用空間,因此無論如何它都會有地址。

如果使用單繼承的對象將與存儲器的第一比特被佈置類似於第一基類進行佈局,然後將內存來保存後的類的成員在鏈中。如果你有任何虛函數,虛擬指針也會有一個地方,可能在開頭。如果你從另一個類型派生出一個類型,你通常會遵循「三個規則」:一個虛擬析構函數,複製構造函數和複製賦值操作符。那麼你將有一個虛擬指針,這可能是4個字節,沒有什麼大不了的。

如果你進入多重繼承,那麼你的對象開始在結構上變得非常複雜。他們會有各種指向自己不同部分的指針,以便函數可以找到他們正在尋找的成員。

這就是說,考慮是否要使用繼承來在所有建模。也許給對象一個bool成員變量將是一個好主意。