2010-09-28 81 views
2

我有一個項目,我有很多相關的信息類,我正在考慮建立一個AbstractInfo類,然後是一堆派生類的層次結構,必要時覆蓋AbstractInfo的實現。然而事實證明,在C++中使用AbstractInfo類來創建一個派生的對象並不那麼簡單。 (請參閱this問題,對最後一個答案的評論)C++工廠和鑄造問題

我打算創建一個工廠類,它創建一個Info對象並始終返回一個AbstractInfo對象。我從C#知道你可以用接口來實現,但在C++中看起來有些不同。

向下鑄造成爲一件複雜的事情,它似乎容易出錯。

有沒有人對我的問題有更好的建議?

+1

你能詳細說明你的意思嗎?不是那麼簡單嗎? – SingleNegationElimination 2010-09-28 08:06:17

+1

一般來說,如果你在'AbstractInfo'中沒有完整的接口,只需要一個問題,即你需要訪問一些只在子類中定義的方法。但是這也可能意味着你的設計不夠理想。這些信息很難再多說。 – 2010-09-28 08:12:33

回答

5

您不需要向下轉換。看到這個例子:

class AbstractInfo 
{ 
public: 
    virtual ~AbstractInfo() {} 
    virtual void f() = 0; 
}; 

class ConcreteInfo1 : public AbstractInfo 
{ 
public: 
    void f() 
    { 
     cout<<"Info1::f()\n"; 
    } 
}; 

class ConcreteInfo2 : public AbstractInfo 
{ 
public: 
    void f() 
    { 
     cout<<"Info2::f()\n"; 
    } 
}; 

AbstractInfo* createInfo(int id) 
{ 
    AbstractInfo* pInfo = NULL; 
    switch(id) 
    { 
    case 1: 
     pInfo = new ConcreteInfo1; 
     break; 

    case 2: 
    default: 
     pInfo = new ConcreteInfo2; 
    } 

    return pInfo; 
} 


int main() 
{ 

    AbstractInfo* pInfo = createInfo(1); 
    pInfo->f(); 
    return 0; 
} 
1

雖然通常你不能在C++返回類型超載,存在來自維基百科covariant return types

實施例的異常:

// Classes used as return types: 
class A { 
} 

class B : public A { 
} 

// Classes demonstrating method overriding: 
class C { 
    A* getFoo() { 
     return new A(); 
    } 
} 

class D : public C { 
    B* getFoo() { 
     return new B(); 
    } 
} 

因此消除了鑄造的需要。

+1

這是不正確的C++。 – SingleNegationElimination 2010-09-28 08:10:47

+1

'extends' - 那是什麼語言?並且你想要返回一個指向新分配對象的指針。那裏也沒有工廠設施。 – 2010-09-28 08:11:28

+1

不是C++代碼。 – Hemant 2010-09-28 08:17:03

2

不要低調 - 使用虛擬方法。只需從工廠返回指向基類的指針,並且只能通過該指針工作。

+0

我看到了...但是如果你做了AbstractInfo * info = new DerivedInfo(),你至少需要讓編譯器知道你需要哪個版本的虛函數,是不是認爲是downcast? – 2010-09-28 08:14:22

+0

來自最派生類的版本將自動調用,不需要downcast。 – sharptooth 2010-09-28 08:16:48

+3

編譯器根本不需要任何幫助來確定使用哪種方法。這就是'虛擬'的功能。當你在一個指針上調用一個虛擬方法時,編譯器知道這個值實際上可能是另一個派生類型。它檢查對象的類型,然後查找相應的虛擬方法。 – SingleNegationElimination 2010-09-28 08:18:31

1
class AbstractInfo 
{ 
    public: 
    virtual ~AbstractInfo(); 
    virtual X f(); 
    ... 
}; 

class Info_1 : public AbstractInfo 
{ 
    ... 
}; 

class Info_2 : public AbstractInfo 
{ 
    ... 
}; 

AbstractInfo* factory(inputs...) 
{ 
    if (conditions where you would want an Info_1) 
     return new Info_1(...); 
    else if (condtions for an Info_2) 
     return new Info_2(...); 
    else 
     moan_loudly(); 
} 

如果不希望工廠方法成爲維護下游客戶端代碼的單點增加了信息的類型,則可以代替提供一些機制,客戶端代碼登記方法用於創建這些派生對象。查看四人幫的設計模式書中的創作模式,或谷歌他們。

0

C++提供polymorphism就像C#一樣。該語言沒有特殊的界面類型,但您可以使用只有pure virtual methods的類來模擬該語言。在C#中,所有方法默認都是虛擬的(意味着它們在運行時綁定),而在C++中,您必須明確使用關鍵字聲明該方法。此外,C#使用引用處理所有對象(據我所知),而在C++中,您必須在值,指針或引用之間進行選擇。在你的情況下,你很可能希望你的工廠返回一個指向接口的指針,或者更好的是smart pointer,所以你不必擔心內存管理。

0

爲了詳細闡述/認識一點,使用抽象接口(例如:具有虛擬函數的基類)的「良好」時間是基本上所有將在對象上使用的功能都可以包含在虛擬函數中的時間。如果是這樣的話,你可以輕鬆地完成你所提出的任務,並且只需要調用基類指針上的虛函數,它就會自動調用所提供的最衍生版本。

如果您發現自己需要經常沮喪以獲取子級特定功能/數據,則此方法可能不適合您的情況。在這種情況下,您可能會發現自己在類的外部編寫了一些功能,爲每種類型提供了多種實現方式,並根據需要使用某種RTTI來幫助降級。這比較麻煩,但是在「學術」或者很好的孤立用法之外更趨於常見。但是,看起來你在其他答案中有很多很好的信息/建議。