仅代码重用 c++ 的继承
Inheritance only for code reuse c++
我有A类和B类。 现在我需要编写一个新的 C 类,它将在 A 和 B 中使用一些字段和方法,但不是全部。(我将使用来自 A 和 B 的大约 50% 的东西)。
现在我正在考虑从 A 和 B 继承。 但是这将使C包含许多没有意义的字段和方法。
基本上,我仅将继承用于代码重用目的,否则我将不得不从 A 和 B 复制和粘贴许多代码行。
这种做法真的很糟糕吗? 有没有不同的方法?
谢谢!
继承没有"是一半"的概念,所以这绝对不是这里的方式。这听起来像是作曲的一个主要案例。
听起来A
和B
有多个"功能",因为它们中的一半足以组成一个C
.
我不确定这是否适用于您的情况,但请考虑将 A 分为两部分,A1
和A2
具有C
所需的功能A1
。然后对B
B1
和B2
执行相同的操作。
然后A
将是A1
和A2
的组合,B
将是B1
和B2
的组合,C
将是A1
和B1
的组合。它们都没有任何不必要的功能或数据。
继承应该使用"is a"范式。
这意味着 C 应该从 A,B 继承,如果它是 A 和 B 的一种。
如果你已经在使用多重继承,你可能想将 A 和 B 分解为多个类,每个类处理一小段代码,然后只从你需要的内容继承 C - 这样 C 将只占用它需要的空间(假设 A 和 B 有很多成员)。
请记住,类的大小不受成员方法的影响,而只受成员数据的影响。
正如Herb Sutter和Andrei Alexandrescu在他们的C++编码标准(第34项)一书中所解释的那样,继承是C++允许你在两个类之间使用的最紧密的关系之一 - 它仅次于类之间的friend
关系。
根据 OO 的 S.O.L.I.D 原则,成功的设计应该以类之间的松散耦合为目标 - 这推断出将依赖关系保持在最低限度;这反过来意味着继承是一种应该谨慎使用的工具。
当然,依赖关系通常需要存在于某个地方,因此合理的折衷方案可以从完全没有实现的类继承(类似于 C# 和 Java 等语言中所谓的interface
)。 例如
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 以更实用的样式重用代码 - 同样,在传递函数对象时通常不涉及紧密的依赖关系。
这很糟糕。仅在逻辑上有意义的情况下使用继承。
改用组合(private
继承是一种组合形式,但最好走老派):
class C
{
A a;
B b;
}
如果C
不是由A
和B
组成,您也可以保留指针,这样C
的大小就不会增加。
听起来你可以从重构你的代码中受益:
取而代之的是:
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!
};
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象