2017-09-01 35 views
3

這是上下文:A Model有一個(指向)ParameteroutputModelParameter是抽象類。我們使用Model*類型的指針來操縱Model的各種派生(具體)類,其指針Parameter動態指向各種衍生(具體)類Parameter的實例。多態性:這是(可能密集型)使用static_cast致命嗎?

下面是一個簡化版本的類作爲例子。我知道new應該避免或至少後跟delete,但我省略了主題代碼行(如析構函數)。

// Abstract classes 
class Parameter { 
public: 
    virtual void reinitialize() = 0; 
}; 

class Model{ 
public: 
    Model(Parameter *argt){ ptr_param = argt; } 
    virtual void computeModelOutput() = 0; 
    double output; 
    Parameter *ptr_param; 
}; 

// Concrete classes 
class ACertainKindOfParameter : public Parameter{ 
public: 
    ACertainKindOfParameter(int argt){ value = argt; } 
    virtual void reinitialize(){ value = 1; } 
    int value; 
}; 

class ACertainKindOfModel : public Model{ 
public: 
    ACertainKindOfModel(int argt) : Model(new ACertainKindOfParameter(argt)){} 
    virtual void computeModelOutput(){ 
     output = 10.0 + (double)(static_cast<ACertainKindOfParameter*>(ptr_param)->value); 
    } 
}; 

int main(){ 
    ACertainKindOfModel myModel{5}; 
    Model *ptr_model = &myModel; 
    ptr_model->computeModelOutput(); 
    std::cout << ptr_model->output << std::endl; // 15 
} 

讓我困擾的這個代碼是ACertainKindOfModelvalue不能直接訪問,所以我顯然需要使用static_cast。真正的Model當然會具有例如每次計算output(或任何其他依賴於參數的動作)時,這將意味着50 static_cast。這對我來說不太好,但我可能是錯的。你看到設計中的缺陷嗎?

注:我覺得做Parameter類模板,但它似乎並沒有一個有效的選擇,因爲Parameter的方法時,不同類型的value被認爲是深有所不同。在上面的簡單示例中,value類型爲int,但是在從Parameter派生的另一類中,它可以是用戶定義的類型,例如, Color只有三個可能的值R,GBreinitialize()會與value = 1有很大不同。 Parameter中的虛擬getter()會很好,但是也不起作用,因爲重定義中的返回類型是衝突的。

+1

你打算怎麼處理價值?如果是計算,請查看[訪問者模式](https://en.wikipedia。org/wiki/Visitor_pattern),所以沒有其他類必須知道它的價值。如果是顯示,可以考慮添加一個虛擬getter,它以'string'的形式返回中性形式的值。 – user4581301

+1

@ user4581301事實上,'value'主要用於計算,如我寫的那段代碼所示,也可能出現在if(value == R)等條件中,等等(特別是value是不是數字)。感謝您對Visitor模式的建議。 – Georg

+0

*「我知道應該避免新的」*。所以使用智能指針:甚至更少的代碼行。 – Jarod42

回答

3

有幾種方法可以使這個更清潔。如果Model不需要訪問ptr_param,則可以將其從Model中刪除,並將其存儲在每個派生類中,並使用正確的類型。

或者你可以封裝在每個模型類中的一個getter函數的static_cast

ACertainKindOfParameter *getParam() const { return static_cast<ACertainKindOfParameter *>(ptr_param); } 

您可以結合這兩種技術。在派生模型類中定義參數,並使用協變返回類型來允許基類Model類訪問。在Model,聲明一個getter:

virtual Parameter *getParam() const = 0; 

然後,在每個模型中,聲明協變重寫:

virtual ACertainKindOfParameter *getParam() const override { return ptr_param; } 

它假定ptr_param是內ACertainKindOfModel聲明。如果不是,您需要按照上述方法應用static_cast

或者您可以將static_cast的結果保存在compute函數中,以避免多次使用它。

+0

我個人的結論是:我嘗試了無數的事情,主要歸結爲最初的'static_cast'。使'參數'模板類幾乎工作,但最終失敗,因爲模板參數演繹[不適用於聲明指針](https://stackoverflow.com/questions/46085683/)。 – Georg