2014-07-03 62 views
5

沒有RTTI和虛擬功能。C++對象的存儲類型,有什麼選擇更好?

我遇到2個不同共同解決方案,以提供物體的類型:

與虛擬方法調用,並保持ID的方法內:

class Base { 
public: 
virtual ~Base(); 
virtual int getType() const =0; 
}; 
class Derived : public Base { 
public: 
virtual int getType() const { return DerivedID; } 
}; 

帶內嵌方法調用,並保持ID基類:

class Base { 
int id_; 
public: 
virtual ~Base(); 
inline int getType() const { return id_; } 
}; 

class Derived : public Base { 
public: 
    Derived() { id_=DerivedID;} 
}; 

什麼是一般的更好的選擇,他們的利弊是什麼?

+6

如果你選擇第二個,而是讓Base的受保護的構造函數將id作爲參數 - 那麼至少它將始終被初始化並且實現者被迫提供它 – stijn

+0

堅持使用接口! –

回答

1

如果您在每個派生類中選擇帶ID的第二個選項,那麼您在每個創建的對象中都會有一個額外的成員。如果你使用虛函數的第一個選項,你將在vtable中有一個額外的指針,每個類只存在一次,而不是每個對象。如果班級將有多個虛擬功能,第一個選項顯然更好。即使不是,我認爲它更符合人們的期望。

+0

你會考慮調用'virtual'函數的運行時間開銷嗎?或者,在現實生活中應用程序太微不足道了?這個選擇對我來說就像_extra運行時存儲與額外的運行時處理一樣_... –

+0

@DrewDormann虛擬函數的開銷既微小又常見,所以我已經學會了在大多數時間不再擔心它。但你是對的。 –

+0

'一個額外的指針在vtable中只存在一次每個類,而不是每個對象'聽起來很明顯錯誤 –

0

你並不需要虛擬繼承從直接基類,或基類成員變量在所有

struct Interface { 
    virtual void foo() = 0; 
    virtual int bar() = 0; 
}; 

template<class T> 
class Base : public Interface { 
public: 
    int getType() const { return getTypeId(); } 
    static int getTypeId() { return T::ClassId; } 
}; 

class Derived : public Base<Derived> { 
public: 
    static const int ClassId = DerivedID; 

    virtual void foo() { } 
    virtual int bar() { return 1; } 

}; 

使用支持該功能就像

Derived der; 
Interface* iface = &der; 
iface->foo(); 
iface->bar(); 

見工作示例here

注:
所有你與這樣的系統的當前配置使用的類型需要在編譯時衆所周知的。這不支持Plugin pattern based機制。

+1

我認爲這打破了在普通基類中存在'getType()'的想法,不是嗎? –

+0

@DrewDormann如果需要,您仍然可以引入一個vtable。但是,由於OP沒有RTTI狀態,它可能無用。我不相信基於'dynamic_cast <>()'的設計真的會帶來好的效果。 –

+0

如果你有一個指向基類的指針或引用,你將如何返回適當的派生ID? CRTP用於編譯時多態,而不是運行時。 –

0

好吧,我帶你去一個刺...

「有什麼利弊/他們的缺點?」

你的第一個例子virtual int getType() const =0;招致額外的處理開銷。函數調用對於CPU來說可能更難以搶佔。 This issue may be trivial

你的第二個例子inline int getType() const { return id_; }招致額外的運行時間存儲。並且每Base的每個實例都存儲額外的int。這也可能是微不足道的。

「一般情況下更好的選擇是什麼?

通常,避免過早優化。選擇基類中的純虛函數,因爲它的正確性由編譯器和運行時強制執行。

相關問題