我有A和B类。现在我需要编写一个新的C类,它将在A和B中使用一些字段和方法,但不是全部。 (我将使用A和B中大约50%的东西)。
现在我正在考虑从A和B继承。但这将使C包含许多没有意义的字段和方法。
基本上我只是为了代码重用而使用继承,否则我将不得不从A和B复制并粘贴多行代码。
这种做法真的很糟糕吗?有不同的方法吗?
谢谢!
答案 0 :(得分:6)
继承没有“是一半”的概念,所以它绝对不是去这里的方式。听起来这是构图的主要案例。
听起来A
和B
有多个“功能”,因为每个功能中有一半足以组成C
。
我不确定这是否适用于您的情况,但考虑将A分为两部分,A1
和A2
以及C
中所需的A1
功能。然后对B
B1
和B2
进行同样的操作。
A
将由A1
和A2
组成,B
将由B1
和B2
和{{组成1}}将是C
和A1
的组合。没有任何必要的功能或数据。
答案 1 :(得分:3)
继承应该使用“是一种”范式 这意味着C应该从A,B继承,如果它是A和B的那种 如果你已经在使用多重继承,你可能想要将A和B分解为多个类,每个类处理一小段代码,然后只从你需要的东西继承C - 这样C只会占用它的空间需求(假设A和B有很多成员) 请记住,类的大小不受成员方法的影响,只受成员数据的影响。
答案 2 :(得分:3)
正如Herb Sutter和Andrei Alexandrescu在他们的书 C++ Coding Standards (item 34) 中解释的那样,继承是C ++允许您在两个类之间使用的最紧密的关系之一 - 它仅次于{ {1}}类之间的关系。
根据S.O.L.I.D principles of OO,成功的设计应该针对类之间的松散耦合 - 这可以将依赖性保持在最低限度;这反过来又暗示继承是一种应该谨慎使用的工具。
当然,依赖关系通常需要存在某处,因此合理的折衷方案可以从没有实现的类继承(类似于所谓的friend
s语言,如C#和Java)。 e.g。
interface
使用这种方法,如果您在多个 Drivable 类之间重用了代码元素,则通常会使用合成或其他较弱的关系来消除重复的代码。
例如也许你想要为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
和lambdas来重用更实用的代码 - 再次传递函数对象时通常不会涉及严格的依赖关系。
答案 3 :(得分:2)
很糟糕。只有在逻辑上有意义时才使用继承。
使用组合代替(private
继承是一种组合形式,但最好是老派):
class C
{
A a;
B b;
}
如果C
不是由A
和B
组成,您也可以改为使用指针,因此C
的大小不会增加。
答案 4 :(得分:0)
听起来您可以从重构代码中受益:
而不是:
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!
};