2015-08-26 45 views
0

在我們的系統,我們有在這種設計中,我可以使用dynamic_cast以外的東西嗎?

  • 多個deviceTypes
  • 每個設備類型可以有不同的配置類型
  • 每個設備類型將是一個圖書館自身的

我在我被迫使用dynamic_cast的情況。我想知道是否有更好的方法來設計這個?

我有什麼是:

// in common code 
class Config {public: virtual ~Config(){} }; 

    class Device { 
    protected: 
     Config* devConfig; 
    protected: 
     virtual void createDevConfig() = 0; 
    public: 
     virtual void display() = 0; 
    }; 

    // Device specific Code 
    class A0Device : public Device { 
    protected: 
     virtual void createDevConfig() { this->devConfig = new A0Config(); } 
    public: 
     A0Device() { this->createDevConfig(); } 

     virtual void display(){ 
     A0Config* config = dynamic_cast<A0Config*>(this->devConfig); 

     if(!config) std::cout << "Null object\n"; 

     } 
    }; 

    class A0Config : public Config {}; 

    int main() { 
     Device* dev = new A0Device(); 
     dev->display(); 
     return 0; 
    } 

本質A0Device有其自己的配置類型:A0Config,它是由其他成員。 A0Device在基類中定義爲Config*。在A0Device::display() - 我需要訪問devConfig對象(如A0Config類型)。 virtual createDevConfig()確保config對象的類型始終爲A0ConfigA0Device =>在這裏使用dynamic_cast安全嗎?有沒有更好的設計方法?

+0

爲什麼A0Device需要一個基類? –

+0

如果您還沒有聽說過[double dispatch](https://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B),請看一看。那是另一個可能的解決方案 –

+0

您可以將'devConfig'字段移動到'A0Device'中,然後將其類型更改爲'A0Config *',因爲它現在只針對'A0Device'。 – immibis

回答

1

你可以在基地裏有一個純虛函數,它返回一個Config指針或引用(我寧願除非你需要一個指針),然後在派生類中有存儲。這個問題/答案覆蓋指針和引用之間的區別:When to use references vs. pointers

這種設計的好處是,在基本任何需要一個Config可以使用getConfig,而任何需要使用派生類可以無需進行轉換。另外你不需要撥打newdelete

class Device { 
    protected: 
     virtual Config& getConfig() = 0; 
    ... 
}; 

class A0Device { 
public: 
    ... 
    Config& getConfig() {return config;} 
    ... 
private: 
    A0Config config; 
}; 
+0

當A0Device getconfig被調用時,你會得到一個配置對象而不是A0Config類型 - 正確嗎? – brainydexter

+0

另外,可以參考指向派生對象嗎? – brainydexter

+0

@brainydexter:對任何'Base'的指針和引用都可能實際上指向/引用給定的'Derived'對象。 – 3442

0

[不知道,如果我失去了一些東西在這裏,但它或多或少聽起來像是一個設計的氣味]

爲什麼不能A0ConfigConfig

很多時候,打在dynamic_cast是一種線索,在建立關係方面有些事情是不正確的。在這種情況下,A0Config提供了一些不符合其基類Config的功能(getA()),或許違反了LSP-Liskov Substitution Principle,從而違反了強的IS-A

儘管如此,If a class relationship can be expressed in more than one way, use the weakest relationship that's practical – Herb Sutter

...和肖恩家長去到這個程度。 Inheritance is the base class of evil

2

如果您可以支持額外的(最小的通用系統,大量的實時/嵌入式系統)運行時間開銷,您可以安全地使用dynamic_cast<>

但是,您必須意識到這個「小」的細節。給出的表達式dynamic_cast<T*>(expr),每當動態類型的*expr既不TT一個子類,表達evalutates爲空指針,nullptr。當然,取消引用nullptr會調用未定義的行爲,並會導致大多數平臺上的崩潰

但是,它可能不值得爲nullptr檢查,如果,只是如果安藤,你知道你的代碼應在這樣的情況崩潰。

因爲C++是兩個湯,冰激凌,土豆,咖啡碗,當然,每個通過Stroustrup的/ C++的commitee的耳朵/心來的想法,有幾個備選方案:

  • 向下轉換static_cast<T*>(expr),雖然這與將其他東西轉換爲其他東西的相同問題不同。
  • 對於發現它「必要」的C人來說,reinterpret_cast<T*>(expr)不是必要的,但它在那裏。
  • 如果覺得這事是土力工程,完美的,如果它的工作原理,你知道所有對象可能在一個地方有在運行時的類型,你可以用placement newunion for holding the data使用enum for the typeexplicit destructor calls supercombo。
  • 如果數據內容涉及到問題,那麼可以在基礎中包含virtual Config &getConfig() = 0之類的內容,並在Derived中包含類似ABC123Config config; Config &getConfig { return this->config; }之類的內容。
  • 對於像我這樣的瘋子只有:使用C風格/構造風格的演員。

希望這有助於!

+0

您能否詳細說明第二個最後的要點? – brainydexter

+0

@brainydexter:你的意思是*如果涉及這些東西...... *點? – 3442

+0

是的:虛擬配置&getConfig()= 0在基地,' – brainydexter

相關問題