2009-02-13 90 views
4

我有一個有趣的問題。考慮這個類層次:具體類具體方法

class Base 
{ 
public: 
    virtual float GetMember(void) const =0; 
    virtual void SetMember(float p) =0; 
}; 

class ConcreteFoo : public Base 
{ 
public: 
    ConcreteFoo("foo specific stuff here"); 

    virtual float GetMember(void) const; 
    virtual void SetMember(float p); 

    // the problem 
    void foo_specific_method("arbitrary parameters"); 
}; 

Base* DynamicFactory::NewBase(std::string drawable_name); 

// it would be used like this 
Base* foo = dynamic_factory.NewBase("foo"); 

我已經離開了DynamicFactory定義以及如何構建器 其註冊。 Builder對象與名稱 相關聯,並將分配Base的具體實現。實際的 實現與shared_ptr處理內存 回收有點複雜,但它們對我的問題並不重要。

ConcreteFoo具有類特定的方法。但是由於具體實例 是在動態工廠中創建的,因此具體類不可知或者可以訪問 ,它們只能在源文件中聲明。我如何 foo_specific_method暴露給Base*的用戶?

我添加了我提出的解決方案作爲答案。我已將它們命名爲 ,因此您可以在答案中輕鬆引用它們。

我不只是尋找我原來的解決方案的意見,新的 將不勝感激。

+0

請讓你的答案社區維基答案!謝謝。 – strager 2009-02-13 21:54:56

+0

或者,完全刪除你的答案。雖然我猜這可能會起作用... – strager 2009-02-13 21:55:41

回答

2

演員會比大多數其他解決方案快,但是:

在基類中添加:

void passthru(const string &concreteClassName, const string &functionname, vector<string*> args) 
{ 
    if(concreteClassName == className) 
     runPassThru(functionname, args); 
} 

private: 
    string className; 
    map<string, int> funcmap; 
    virtual void runPassThru(const string &functionname, vector<string*> args) {} 

在每個派生類:

void runPassThru(const string &functionname, vector<string*> args) 
{ 
    switch(funcmap.get(functionname)) 
    { 
     case 1: 
      //verify args 
      // call function 
     break; 
     // etc.. 
    } 
} 

// call in constructor 
void registerFunctions() 
{ 
     funcmap.put("functionName", id); 
     //etc. 
} 
0

將特殊功能添加到Base

最簡單和最不可接受的解決方案是將 foo_specific_method添加到Base。然後,不使用 的類可以將其定義爲空。這不起作用,因爲 用戶被允許使用 dynamic_factory註冊他們自己的建造者。新班級也可能有具體的班級 具體方法。

本着這種解決方案的精神,稍微好一點。將通用 函數添加到Base

class Base 
{ 
    ... 
    /// \return true if 'kind' supported 
    virtual bool concrete_specific(int kind, "foo specific parameters"); 
}; 

這裏的問題是 concrete_specific對不同參數集的有可能相當多的過載。

0

只需施放它。

當需要特定的方法時,通常您知道 Base*實際上是ConcreteFoo。因此,只要確保類的定義 ConcreteFoo爲方便和:

ConcreteFoo* foo2 = dynamic_cast<ConcreteFoo*>(foo); 

一個我不喜歡這種解決方案的原因是dynamic_casts很慢, 需要RTTI。

下一步是避免dynamic_cast。

ConcreteFoo* foo_cast(Base* d) 
{ 
    if(d->id() == the_foo_id) 
    { 
     return static_cast<ConcreteFoo*>(d); 
    } 

    throw std::runtime_error("you're screwed"); 
} 

這就需要在基類多一個方法,其是完全可接受的 ,但它需要的ID進行管理。當用戶可以在動態工廠中註冊他們自己的建造者時,難以獲得 。

我不太喜歡任何鑄造解決方案,因爲它需要在使用專門方法的地方定義 用戶類。 但也許我只是一個範圍納粹。

1

CrazyMetaType解決方案。

該解決方案沒有經過深思熟慮。我希望有人可能 有類似的經驗。我看到這適用於 已知類型的未知數的問題。這非常漂亮。我 想將它應用到未知類型的未知數量的***秒***

的基本思想是CrazyMetaType收集參數是類型 安全的方式,然後執行具體的具體方法。

class Base 
{ 
    ... 
    virtual CrazyMetaType concrete_specific(int kind) =0; 
}; 

// used like this 
foo->concrete_specific(foo_method_id) << "foo specific" << foo_specific; 

我的一個擔心這個解決方案是CrazyMetaType將是 出奇的複雜,得到這個工作。我願意接受這個任務,但我不能指望將來的用戶成爲C++專家,只需添加 一個具體的具體方法即可。

0

cstdarg解決方案。

Bjarn Stroustrup的說:

良好定義的程序需要的量, 參數類型不完全指定至多幾個函數。重載函數和使用默認參數 功能時,可以使用一個原本考慮離開 參數類型未指定的照顧類型 在大多數情況下檢查。只有當雙方的論點 參數的類型而異數,是必要的省略號

class Base 
{ 
    ... 
    /// \return true if 'kind' supported 
    virtual bool concrete_specific(int kind, ...) =0; 
}; 

這裏的缺點是:

  • 幾乎沒有人知道如何使用cstdarg正確
  • 它不會覺得非常C++ - y
  • 它不是類型安全的。
0

您可以創建Base的其他非具體子類,然後在DynamicFactory中使用多個工廠方法嗎?

你的目標似乎是顛覆子類化的觀點。我很想知道你在做什麼需要這種方法。

0

如果具體對象具有類特定的方法,那麼它意味着你只可以明確調用該方法時,你正在處理的類的實例,而不是當你處理與通用基礎類。這是關於你正在運行一個switch語句的b/c檢查對象類型嗎?

我從不同的角度接近這個,使用「不可接受的」第一解決方案,但不帶參數,與具有將存儲它的狀態成員變量的具體對象。雖然我猜這會迫使你有一個成員關聯數組作爲基類的一部分,以避免強制設置狀態。

您也可能想嘗試一下Decorator模式。

0

你可以做一些類似的CrazyMetaType或cstdarg說法,但簡單和C++ - ISH。 (也許這可能是SaneMetaType。)只需爲參數concrete_specific定義一個基類,並使人們從中派生出特定的參數類型。像

class ConcreteSpecificArgumentBase; 

class Base 
{ 
    ... 
    virtual void concrete_specific(ConcreteSpecificArgumentBase &argument) =0; 
}; 

當然了什麼,你會需要RTTI來出來的東西concrete_specific每個版本中進行排序。但如果ConcreteSpecificArgumentBase設計得很好,至少它會讓concrete_specific相當簡單。

0

怪異的一部分是, DynamicFactory的用戶會收到一個Base類型,但是當它是ConcreteFoo時需要做特定的事情。

也許不應該使用工廠。

嘗試一下像創建ConcreteFoo自己其他的依賴注入機制,通過一個ConcreteFoo類型的指針那些誰需要它,一個基本類型指針等。

0

的情況下,似乎假定用戶將與您ConcreteType合作,並知道它是這樣做的。

在這種情況下,似乎你可以在你的工廠另一種方法,返回ConcreteType *,如果客戶知道他們正在處理的具體類型和需要抽象的那個水平的工作。