我有類A和B.現在我需要編寫一個新的類C,它將在A和B中使用一些字段和方法,但不是全部。 (我將使用A和B中50%的東西)。繼承僅用於代碼重用C++
現在我正在考慮繼承A和B,但是這會讓C包含很多沒有意義的字段和方法。
基本上我只用了代碼重用的目的繼承,否則我將不得不復制和A和B.
粘貼多行代碼,這種做法真的不好?有不同的方法嗎?
謝謝!
我有類A和B.現在我需要編寫一個新的類C,它將在A和B中使用一些字段和方法,但不是全部。 (我將使用A和B中50%的東西)。繼承僅用於代碼重用C++
現在我正在考慮繼承A和B,但是這會讓C包含很多沒有意義的字段和方法。
基本上我只用了代碼重用的目的繼承,否則我將不得不復制和A和B.
粘貼多行代碼,這種做法真的不好?有不同的方法嗎?
謝謝!
這是不好的。只有在邏輯上有意義時才使用繼承。
使用成分代替(private
繼承的組成形式,但最好還是老派):
class C
{
A a;
B b;
}
如果C
不是由A
和B
,您還可以保持指針代替,所以C
的大小不會增加。
繼承應該使用「是」範例。
這意味着C應該繼承自A,B,如果它是A和B的一種。
如果您已經在使用多繼承,您可能需要將A和B分解爲多個類,每個類都處理一小段代碼,然後只從你需要的C繼承C - 這樣C只會佔用它需要的空間(假設A和B有很多成員)。
請記住,您的類的大小不受成員方法影響,只有成員數據。
在C++中,* public *繼承意味着「is-a」 。其他層次的繼承意味着不同的東西......比如「被實現的東西」。 – cHao
@cHao - 這是真的,但即使有私有繼承 - C有權訪問它不需要的代碼部分是一種不好的做法。此外 - 如果A和B有許多數據成員,C的大小仍然會比它應該大。 –
繼承沒有「是一半」的概念,所以絕對不是這裏的路。這聽起來像是構圖的一個主要情況。
聽起來好像A
和B
有一個以上的「功能」,因爲他們中的一半都足以組成C
。
我不知道這是適合你的情況,但考慮打破了分成兩個部分,A1
和A2
與在A1
C
所需的功能。然後將B
轉換爲B1
和B2
。然後
A
將是A1
和A2
的組合物,B
將是B1
和B2
和C
的組合物將是A1
和B1
的組合物。他們都沒有任何不必要的功能或數據。
由於香草薩特和安德烈Alexandrescu的在他們的著作C++ Coding Standards (item 34),繼承是C++允許你兩個類之間使用最緊密的關係的一個解釋 - 這是僅次於類之間的關係friend
。
根據S.O.L.I.D principles of OO,一個成功的設計應該旨在寬鬆類之間的耦合 - 這推斷保持依賴關係的最低限度;這又意味着繼承是一個應該謹慎使用的工具。
當然,通常需要依賴關係存在地方,所以一個合理的妥協可以從類中繼承與所有沒有實現(類似於所謂interface
S IN的語言,如C#和Java)。例如
class IDriveable
{
public:
virtual void GoForward() = 0;
virtual void GoBackward() = 0;
};
class Car : public IDriveable { /* etc. */ };
class Bus : public IDriveable { /* etc. */ };
class Train : public IDriveable { /* etc. */ };
通過這種方法,如果有其若干驅動類之間重複使用的代碼元素中,一般會使用組合物或一些其它較弱的關係,以消除重複的代碼。
例如也許你想重用代碼TurnLeft
爲Bus
和Car
但不是Train
左轉是不合邏輯的,所以TurnLeft
可能最終成爲一個單獨的類,它是Bus
和Car
的成員。
最終的結果可能是少量額外的編寫代碼,但通常是一個不太複雜的設計,通常是一個更容易管理的代碼。設計這樣的代碼沒有任何硬性規則,因爲它完全取決於你試圖解決的獨特問題。
還有其他的方法來重用代碼,而無需緊密耦合太 - 模板可以讓你含蓄地定義接口不含純virtual
功能(模板提供額外的類型安全空類 - 這是一個非常好的事情,但他們在語法上一個更復雜一點);
還有一些方法可以使用std::function
和lambda來重用更具功能性的代碼 - 在傳遞函數對象時通常也沒有緊密的依賴關係。
這聽起來像你可以從重構你的代碼中受益:
取而代之的是:
class A
{
virtual void foo();
virtual void bar();
};
class B
{
virtual void biz();
virtual void baz();
};
class C : public A, public B
{
virtual void foo() { /* my stuff */ }
virtual void biz() { /* my other stuff */ +
// but I don't need bar or baz!
};
考慮分拆出來,你用C要A和B的概念上不同的部分:
class core_A
{
virtual void foo();
};
class A : public core_A
{
virtual void bar();
};
class core_B
{
virtual void biz();
};
class B : public core_B
{
virtual void baz();
};
class C : public core_A, public core_B
{
virtual void foo() { /* my stuff */ }
virtual void biz() { /* my other stuff */ +
// Great, I don't have bar or baz!
};
謝謝你們的回覆!我非常感謝他們。我考慮使用繼承而不是組合的原因是因爲我還需要修改A和B中的一些行爲。另外,我並不想編輯A和B. – user1657624