pae*_*bal 253
多重继承(缩写为MI)闻起来,这意味着通常,它是出于不好的原因而完成的,它会在维护者面前反击.
这对于继承来说是正确的,因此,对于多重继承来说更是如此.
你的对象真的需要从另一个继承吗?A Car不需要继承Engine工作,也不需要继承Wheel.A Car有Engine四个Wheel.
如果你使用多重继承来解决这些问题而不是组合,那么你做错了.
通常情况下,你有一个类A,然后B和C来自继承A.而且(不要问我为什么)有人然后决定D必须继承B和C.
我在8个8年里遇到过这种问题两次,看到因为:
D不应该从两个继承B和C),因为这是不好的架构(其实,C不应该存在在所有...)A在其孙子类中出现了两次D,因此,更新一个父字段A::field意味着更新它两次(通过B::field和C::field),或者有一些东西是默认错误并且崩溃,之后(新的指针B::field,并删除C::field...)如果这不是你想要的,那么在C++中使用关键字virtual来限定继承可以避免上面描述的双重布局,但无论如何,根据我的经验,你可能做错了......
在对象层次结构中,您应该尝试将层次结构保持为树(节点具有一个父节点),而不是图形.
C++中的恐惧钻石的真正问题(假设设计合理 - 让你的代码得到审查!),你需要做出选择:
A在你的布局中存在两次,这是什么意思?如果是,那么一定要从它继承两次.这个选择是问题所固有的,而且在C++中,与其他语言不同,您实际上可以在没有教条的情况下执行此操作,从而在语言级别强制设计.
但是像所有权力一样,拥有这种权力的责任就在于:让您的设计得到审查
零或一个具体类的多重继承,以及零个或多个接口通常是好的,因为您不会遇到上述的恐惧钻石.事实上,这就是用Java完成的事情.
通常情况下,你的意思是当C从继承A和B是用户可以使用C,如果它是一个A,和/或如果它是一个B.
在C++中,接口是一个抽象类,它具有:
零到一个真实对象以及零个或多个接口的多重继承不被认为是"臭"(至少不是那么多).
首先,NVI模式可用于生成接口,因为真正的标准是没有状态(即没有成员变量,除了this).你的抽象界面的意思是发布合同("你可以用这种方式打电话给我,这样"),仅此而已.仅具有抽象虚拟方法的限制应该是设计选择,而不是义务.
其次,在C++中,从抽象接口虚拟继承是有意义的(即使有额外的成本/间接).如果不这样做,并且接口继承在层次结构中出现多次,那么您将有歧义.
三,面向对象是伟大的,但它不是唯一的真理在那里TM在C++中.使用正确的工具,并始终记住您在C++中提供其他范例,提供不同类型的解决方案.
有时候是.
通常情况下,你的C类继承A和B,和A和B是两个不相关的对象(即不在同一层次,没有任何共同之处,不同的概念,等等).
例如,您可以拥有一个Nodes具有X,Y,Z坐标的系统,能够进行大量的几何计算(可能是一个点,几何对象的一部分),每个节点都是一个自动代理,能够与其他代理进行通信.
也许您已经可以访问两个库,每个库都有自己的命名空间(使用命名空间的另一个原因......但是你使用命名空间,不是吗?),一个正在存在geo,另一个存在ai
所以你有自己的own::Node衍生出来ai::Agent和geo::Point.
这是你应该问自己是否不应该使用构图的那一刻.如果own::Node真的真的是a ai::Agent和a geo::Point,那么组合就不行了.
然后,您将需要多重继承,own::Node根据他们在3D空间中的位置与其他代理进行通信.
(你会注意到ai::Agent并且geo::Point完全,完全,完全不相关......这大大降低了多重继承的危险)
还有其他情况:
this)有时你可以使用成分,有时MI更好.关键是:你有一个选择.负责任地做(并检查您的代码).
大部分时间,根据我的经验,没有.MI是不正确的工具,即使它似乎工作,因为它可以由惰性用来堆特征组合在一起而没有意识到后果(如制作Car既有Engine和Wheel).
但有时候,是的.而在那个时候,没有比MI更好的了.
但是因为MI很臭,所以要准备好在代码审查中捍卫你的架构(并且保护它是一件好事,因为如果你无法保护它,那么你就不应该这样做).
Nem*_*vic 141
人们非常正确地说你不需要多重继承,因为你可以用多重继承做任何事情,你也可以用单继承做.你只需使用我提到的委托技巧.此外,您根本不需要任何继承,因为您使用单继承执行的任何操作也可以通过转发类来进行继承.实际上,您也不需要任何类,因为您可以使用指针和数据结构来完成所有操作.但是你为什么要那样做呢?什么时候使用语言设施方便?你什么时候想要一个解决方法?我已经看到了多继承很有用的情况,我甚至看到过很复杂的多继承很有用的情况.通常,我更喜欢使用该语言提供的功能来进行变通
小智 38
没有理由避免它,它在情况下非常有用.但您需要了解潜在的问题.
最大的一个是死亡钻石:
class GrandParent;
class Parent1 : public GrandParent;
class Parent2 : public GrandParent;
class Child : public Parent1, public Parent2;
Run Code Online (Sandbox Code Playgroud)
您现在在Child中有两个GrandParent"副本".
C++已经想到了这一点,并允许你做虚拟继承来解决问题.
class GrandParent;
class Parent1 : public virtual GrandParent;
class Parent2 : public virtual GrandParent;
class Child : public Parent1, public Parent2;
Run Code Online (Sandbox Code Playgroud)
始终检查您的设计,确保您没有使用继承来节省数据重用.如果你可以用组合表示相同的东西(通常你可以),这是一个更好的方法.
公共继承是一种IS-A关系,有时一个类将是几个不同类的类型,有时反映这一点很重要.
"Mixins"有时也很有用.它们通常是小类,通常不从任何东西继承,提供有用的功能.
只要继承层次结构相当浅(因为它应该几乎总是如此),并且管理得当,您就不可能获得可怕的钻石继承.钻石对于使用多重继承的所有语言来说都不是问题,但是C++对它的处理经常是尴尬的,有时令人费解.
虽然我遇到了多重继承非常方便的情况,但它们实际上相当罕见.这可能是因为当我不需要多重继承时,我更喜欢使用其他设计方法.我更愿意避免混淆语言结构,并且很容易构建继承案例,你必须非常好地阅读手册以弄清楚发生了什么.
你不应该"避免"多重继承,但你应该意识到可能出现的问题,如"钻石问题"(http://en.wikipedia.org/wiki/Diamond_problem),并小心对待给你的力量,你应该拥有所有权力.
| 归档时间: |
|
| 查看次数: |
81149 次 |
| 最近记录: |