2010-05-28 44 views
0

我已經構建了幾個類(AB,C ...),它們在同一個BaseClass上執行操作。例如:如何給C++類(接口)提供屬性

struct BaseClass { 
    int method1(); 
    int method2(); 
    int method3(); 
} 
struct A { int methodA(BaseClass& bc) { return bc.method1(); } } 
struct B { int methodB(BaseClass& bc) { return bc.method2()+bc.method1(); } } 
struct C { int methodC(BaseClass& bc) { return bc.method3()+bc.method2(); } } 

但你可以看到,每個班ABC ...只有使用的BaseClass的可用方法的子集,我想給BaseClass分成幾個塊,使得很清楚它使用了什麼,什麼不是。例如,一個解決方案是使用多重繼承:

// A uses only method1() 
struct InterfaceA { virtual int method1() = 0; } 
struct A { int methodA(InterfaceA&); } 

// B uses method1() and method2() 
struct InterfaceB { virtual int method1() = 0; virtual int method2() = 0; } 
struct B { int methodB(InterfaceB&); } 

// C uses method2() and method3() 
struct InterfaceC { virtual int method2() = 0; virtual int method3() = 0; } 
struct C { int methodC(InterfaceC&); } 

的問題是,我每增加一個新類型的操作時間,我需要改變的BaseClass實施。例如:

// D uses method1() and method3() 
struct InterfaceD { virtual int method1() = 0; virtual int method3() = 0; } 
struct D { int methodD(InterfaceD&); } 

struct BaseClass : public InterfaceA, public InterfaceB, public InterfaceC 
// here I need to modify the existing code to add class D 
{ ... } 

你知道一個乾淨的方式,我可以做到這一點嗎?

感謝您的幫助

編輯:

我忘了提及,它也可以使用模板來完成。但是我不喜歡這個解決方案,因爲所需的接口沒有在代碼中明確顯示。您必須嘗試編譯代碼以驗證所有必需的方法是否正確實施。另外,它需要實例化不同版本的類(每個BaseClass類型模板參數一個),這並非總是可能,也不是期望的。

回答

0

使用模式Adapter

struct InterfaceA { virtual int method1() = 0; } 

struct A { int methodA(InterfaceA& bc) { return bc.method1(); } } 

struct BaseClassAdapterForA: public InterfaceA 
{ 
    BaseClassAdapterForA(BaseClass& _bc) : bc(_bc) {} 
    virtual int method1() 
    { 
     //note that the name of BaseClass method 
     //can be anything else 
     return bc.method1(); 
     // or return bc.whatever(); 
    } 
private: 
    BaseClass& bc; 
}; 
//usage 
BaseClass bc; 
A a; 
BaseClassAdapterForA bca(bc); 
a.methodA(bca); 
+0

這正是我需要的!謝謝 – caas 2010-05-31 19:20:53

0

我看到一個派生類沒有錯,沒有使用它的基類的一些元素。

派生類不是,也不應該被要求使用所有可用的

因此,我沒有看到你的原始實現沒有錯,也沒有必要重構它。

+0

嗨,感謝您花時間回答。 事實是:類'A'只需要實現'InterfaceA'的類。使'A'依賴/ BaseClass的所有方法使得重用很困難。例如,要求'BaseClass2'實現'BaseClass'的所有方法就太痛苦了,因爲我希望能夠用'A'(而不是''B'或'C')來使用它。 你明白了嗎? – caas 2010-05-28 18:49:49

0

methodA,methodB,...的調用者應該知道實際使用哪種方法1,2,3?

如果他們這樣做,你可能分裂了BaseClass的在3間不同的接口,並準確地加用方法1,2和3所需要的接口參數,就像這樣:

class Interface1 {virtual int method1() = 0;}; 
class Interface2 {virtual int method2() = 0;}; 
class Interface3 {virtual int method3() = 0;}; 

class A 
    { 
    int methodA(Interface1 &i1) 
     { 
     return i1.method1(); 
     } 
    }; 

class B 
    { 
    int methodB(Interface1 &i1, Interface2 &i2) 
     { 
     return i1.method1() + i2.method2(); 
     } 
    }; 

class C 
    { 
    int methodC(Interface2 &i2, Interface3 &i3) 
     { 
     return i2.method2() + i3.method3(); 
     } 
    }; 

調用者仍然可以選擇爲繼承多個接口,如:

class MyClass : public Interface2, public Interface3 
    { 
    int method2() {...} 
    int method3() {...} 
    }; 
... 
MyClass myClass; 
C c; 
c.methodC(myClass,myClass); 
+1

不要忘記,在C++'method1()','method2()'和'method3()'必須是虛擬的,否則多態性將無法啓動。 – 2010-05-28 22:13:15

+1

取決於'BaseClass :: methodN'的作用,使方法變爲虛擬是沒有必要的。此外,非虛擬接口總有可能。 (http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface) – ablaeul 2010-05-29 16:54:57

+0

@在硅片上,你是對的。我有點倉促。編輯它使其再次正確。 – Patrick 2010-05-30 08:55:13