2011-05-14 149 views
5

鑑於傳統代碼的覆蓋方法,該系統具有的類層次結構如下:爲家庭子類

  Base 
     ^
      | 
----------+--------------- 
^ ^ ^ ^ ^
|  |  |  |  | 
A1  B1 C1 D1 E1 
^ ^ ^ ^ ^
|  |  |  |  | 
A2  B2 C2 D2 E2 
....... 
^ ^ ^ ^ ^
|  |  |  |  | 
An  Bn Cn Dn En 

層次結構表示在某些特定域的消息。

基地類當然是所有消息的基類。 A1..E1是屬於版本1的域的消息,A2..E2到版本2等等。請注意,An必須直接從An-1繼承,因爲An覆蓋了An-1的特定方法。

所有消息都有一些共同的功能,所以它被定義爲Base :: PerformFunctionality。功能的某些部分僅限於版本n,所以存在虛擬功能Base :: SpecificPartOfFunctionality,其被Base :: PerformFunctionality調用。

所以我的問題是如何覆蓋所有An..En的Base :: SpecificPartOfFunctionality

我看到2個可能的解決方案,我不喜歡太:

  1. 實施基地::每個SpecificPartOfFunctionality和每個An..En。

    該解決方案的問題是,對於每個類的實現應該是完全相同,所以我只是重複該代碼。

    其他問題是,如果引入了新類Fn,開發人員可能會忘記執行SpecificPartOfFunctionality

  2. 從基地介紹BASEN類導出,而每個從An..En BASEN太導出:

    class BaseN : public Base { 
        //... 
        SpecificPartOfFunctionality() { ...} 
    }; 
    
    class An: public An-1, public BaseN { .. } 
    

    這種解決方案的問題是,它引入了金剛石問題。

    另外一個問題是會發生什麼,如果其他一些版本需要重寫基地:: SpecificPartOfFunctionality了。繼解決方案後,我們將介紹BaseM,這將覆蓋Base :: SpecificPartOfFunctionality。所以哪個SpecificPartOfFunctionality將要求 - 的基本N基本N。這是完全混亂。

有什麼建議嗎?

+0

您可以更改A1..E1類嗎?如果是這樣的話,爲什麼不實施'SpecificBase'來實現A1..E1派生的'SpecificPartsOfFunctionality',在一個單一的繼承方案中。 'SpecificBase'當然是從'Base'派生的。 – Constantinius 2011-05-14 21:02:31

+0

我可以改變A1 ... E1。我想你正在描述我提出的解決方案2。 – dimba 2011-05-14 21:07:20

+0

不完全,因爲你使用多重繼承(嗯......你的語法看起來不正確。) – Constantinius 2011-05-14 21:10:47

回答

3
struct Base { 
    virtual void PerformFunctionality() { 
    stuff(); 
    SpecificPartOfFunctionality(); 
    more_stuff(); 
    } 
private: 
    virtual void SpecificPartOfFunctionality() {} 
}; 

template<class Prev> 
struct Version3 : Prev { 
protected: // Not private if v4's override might need to call this. 
    virtual void SpecificPartOfFunctionality() { 
    v3_specific_stuff(); 
    } 
}; 

struct A1 : Base {}; 
struct A2 : A1 {}; 
struct A3 : Version3<A2> {}; 

struct B1 : Base {}; 
struct B2 : B1 {}; 
struct B3 : Version3<B2> {}; 

唯一的缺點是你不能輕易向前當前的C++構造,並可能將永遠使用默認的構造函數A2和B2只是爲了簡單起見。

在C++ 0x中,但是,您可以轉發構造函數:

template<class Prev> 
struct Version3 : Prev { 
    using Prev::Prev; 
    //... 
}; 

struct C2 : C1 { 
    C2(int); // No default constructor. 
}; 
struct C3 : Version3<C2> { 
    C3() : Version3<C2>(42) {} 
}; 

請注意,必須直接從-1繼承,由於覆蓋的-1的具體方法。

你誤會了一些東西。 An不需要從An-1直接繼承。例如,這工作得很好:

struct Example { 
    virtual void f(); 
}; 

template<class B> 
struct Intermediate : B {}; 

struct Concrete : Intermediate<Example> { 
    virtual void f(); // Overrides Example::f. 
}; 

請記住,如果這個沒有的工作,那麼你的無法從你的基類擺在首位覆蓋SpecificPartOfFunctionality!在您的任何示例中,An不會直接從Base繼承。

+0

An應直接從An-1派生的事實與我的問題無關。 An是An-1的一個子類型,因此An-1定義了一些被An覆蓋的虛擬函數。 – dimba 2011-05-14 22:17:24

+1

但是他的上面的代碼仍然有效。直接就是錯誤的術語。 An應該從An-1派生(不一定直接)。 – 2011-05-14 22:45:41

+0

@ChristianRau,是的,你說的對 – dimba 2011-05-15 04:04:25

1

在全局範圍內定義一個實現該功能的朋友函數,並且只需調用它即可。例如。

void FunctionalityN(Base* b) 
{ 
    b->DoThings(); 
    ... 
} 

class An : public Base 
{ 
    friend void FunctionalityN(); 
    virtual void SpecificPartOfFunctionality() { FunctionalityN(this); } 
    .... 
}; 

嚴格來說FunctionalityN甚至不需要成爲朋友,儘管它會讓事情變得簡單。這使得直接延伸到Fn,Gn等,並且隨後用NewFunctionalityN替代FunctionalityN也很容易。

+0

+1 @Matt。這是解決方案1的改進的改進,但它在An..En中有一個針對SpecificPartOfFunctionality()的實現。 – dimba 2011-05-14 21:29:44

+0

@dimba對。這並不能完全消除代碼重複,儘管它確實將它最小化了,所以它可能是一個可以接受的折衷方案,因爲在通用性(所有方法之一)和可伸縮性(可能隨後被覆蓋)之間存在固有的緊張關係,不能改變基地(我假設)。我注意到如果你可以在'Base'或其他地方聲明'SpecificPartOfFunctionality'純虛擬,那麼你就避免了將來的開發者忘記覆蓋它的問題。 – 2011-05-14 21:41:34

+0

不,這不會避免未來開發者忘記重寫它的問題。因爲1)更高版本,例如A9,你首先在A3中重寫SpecificPart,必須考慮是否需要重寫它,如果它們沒有編譯錯誤,但是2)如果它是純虛擬的,那麼不需要SpecificPart的A1和A2可以'將被實例化! – 2011-05-14 22:02:00