关于c ++:继承和多态-易用性与纯度

关于c ++:继承和多态-易用性与纯度

Inheritance and Polymorphism - Ease of use vs Purity

在一个项目中,我们的团队使用对象列表对应该以相似方式处理的所有数据集执行批量操作。尤其是,不同的对象在理想情况下将发挥相同的作用,而使用多态性很容易实现。我有一个问题,就是继承暗示了是关系,而不是有关系。例如,多个对象都有一个损坏计数器,但是为了使它易于在对象列表中使用,可以使用多态性-除非那意味着a是不正确的关系。 (人不是损坏计数器。)

我能想到的唯一解决方案是让类的成员在隐式转换时返回正确的对象类型,而不是依赖于继承。放弃一个/理想的选择以换取易于编程的方法会更好吗?

编辑:
更具体地说,我正在使用C ++,因此使用多态性将使不同的对象"发挥相同的作用",即派生的类可以驻留在单个列表中,并可以由基类的虚函数进行操作。接口的使用(或通过继承模仿它们)似乎是我愿意使用的解决方案。


我认为您应该实现接口以能够实现与您的关系(在C#中这样做):

1
2
3
4
5
public interface IDamageable
{
    void AddDamage(int i);
    int DamageCount {get;}
}

您可以在您的对象中实现此目的:

1
2
3
public class Person : IDamageable

public class House : IDamageable

而且,您将确保DamageCount属性并具有一种允许您添加损坏的方法,而并不意味着人和房屋在某种层次结构中彼此相关。


这可以使用多重继承来完成。在特定情况下(C ++),可以将纯虚拟类用作接口。这使您可以进行多重继承而不会产生范围/模糊性问题。例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Damage {
    virtual void addDamage(int d) = 0;
    virtual int getDamage() = 0;
};

class Person : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d * 2;
    }

    int getDamage() {
        return damage;
    }
};

class Car : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d;
    }

    int getDamage() {
        return damage;
    }
};

现在,Person和Car'is-a'Damage都意味着实现了Damage接口。纯虚拟类的使用(使它们像接口一样)是关键,应经常使用。它使将来的更改与更改整个系统保持隔离。阅读有关开放式原则的更多信息。


我同意乔恩的观点,但是假设您仍然需要单独的损坏计数器类,则可以执行以下操作:

1
2
3
4
5
6
class IDamageable {
  virtual DamageCounter* damage_counter() = 0;
};
class DamageCounter {
  ...
};

然后,每个可损坏的类都需要提供自己的Damage_counter()成员函数。这样做的缺点是,它为每个可损坏的类创建一个vtable。您可以改用:

1
2
3
4
5
6
class Damageable {
 public:
  DamageCounter damage_counter() { return damage_counter_; }
 private:
  DamageCounter damage_counter_;
};

但是,当多个父项具有成员变量时,许多人就不容易拥有多重继承。


多态不需要继承。多态是当多个对象实现相同的消息签名(方法)时得到的结果。


@安德鲁

The ideal of"acting the same" and polymorphism are absolutely unrelated. How does polymorphism make it easy to achieve?

它们都具有例如共同的功能。我们称之为addDamage()。如果您想做这样的事情:

1
2
foreach (obj in mylist)
    obj.addDamage(1)

然后,您需要动态语言,或者需要它们从公共父类(或接口)扩展。例如。:

1
2
3
4
5
class Person : DamageCounter {}
class Car : DamageCounter {}

foreach (DamageCounter d in mylist)
    d.addDamage(1)

然后,您可以在某些非常有用的情况下将PersonCar视为相同。


从长远来看,"做对了"将有好处,只要是因为以后维护该系统的人会发现,如果从一开始就做对了,就会更容易理解。

根据语言的不同,您可能会选择多重继承,但是通常简单的接口最有意义。"简单"是指制作一个不会过多尝试的界面。最好有许多简单的接口和一些整体的接口。当然,总会有一个权衡取舍,太多的接口可能会导致有关"接口"被"遗忘" ...


@凯文

Normally when we talk about 'is a' vs 'has a' we're talking about Inheritance vs Composition.

Um...damage counter would just be attribute of one of your derived classes and wouldn't really be discussed in terms of 'A person is a damage counter' with respect to your question.

将损坏计数器作为属性不能使他将带有损坏计数器的对象分类为一个集合。例如,一个人和一辆汽车可能都具有损坏计数器,但是大多数语言中不能包含vectorvector或类似内容。如果您有一个通用的Object基类,则可以以这种方式推入它们,但是您将无法通用地访问getDamage()方法。

在我阅读时,这是他问题的实质。"为了将某些对象视为相同,即使它们不是相同的,我是否应该违反is-ahas-a?"


这个问题确实令人困惑:/

您的粗体问题非常开放,回答为"取决于",但是您的示例并未真正提供有关所询问的上下文的太多信息。这些话使我感到困惑。

sets of data that should all be processed in a similar way

有什么办法?集合是否由函数处理?另一个班?通过虚拟功能对数据进行处理?

In particular, different objects would ideally act the same, which would be very easily achieved with polymorphism

"相同"的理想和多态性是绝对无关的。多态如何使其易于实现?


通常,当我们谈论"是一个"与"有一个"时,我们是在谈论继承与组合。

嗯……损坏计数器只是您派生类之一的属性,对于您的问题,实际上不会以"一个人是一个损坏计数器"的形式进行讨论。

看到这个:

http://www.artima.com/designtechniques/compoinh.html

这可能会对您有帮助。

@Derek:从措辞上来说,我假设有一个基本的说法,重新阅读了我现在有点想知道他在说什么的问题。


有时值得放弃现实的理想。如果这将导致一个巨大的问题,即"做对了"却没有真正的好处,那么我会做错了。话虽如此,我经常认为花点时间做对是值得的,因为不必要的多重继承会增加复杂性,并且可能导致系统的可维护性降低。您确实必须决定哪种情况最适合您的情况。

一种选择是让这些对象实现Damageable接口,而不是从DamageCounter继承。这样,一个人有一个损坏计数器,但是很容易损坏。 (我经常发现接口比名词更容易形容词。)然后,您可以在Damageable对象上具有一致的损伤接口,而不必暴露损伤计数器是基础实现(除非您需要)。

如果您想走模板路线(假设使用C ++或类似的语言),则可以使用mixins来做到这一点,但是如果做得不好,那会很快变得很丑陋。


推荐阅读

    Python之可迭代对象、迭代器、生成器

    Python之可迭代对象、迭代器、生成器,迭代,生成器,一、概念描述可迭代对象就是可以迭代的对象,我们可以通过内置的iter函数获取其迭代器,可

    应用程序对象

    应用程序对象,,应用程序对象是一个应用程序级对象,用于在所有用户之间共享信息,并且在Web应用程序运行期间可以保存数据。 应用的性质: 方法

    Java创建对象的几种方式

    Java创建对象的几种方式,对象,方法,本文目录Java创建对象的几种方式java中几种创建对象的方式1Java中创建对象的集中方式有那些JAVA创建对

    wps快速的编辑图层|WPS巧用对象图层

    wps快速的编辑图层|WPS巧用对象图层,图层,编辑,快速,wps,1.WPS 如何巧用对象图层一、认识对象图层工具及按纽1、您可以在插件工具栏中可以

    空对象快捷键|空白对象快捷键

    空对象快捷键|空白对象快捷键,,空白对象快捷键以win7系统为例1.在键盘上找到Ctrl➕alt➕delete同时按下2.出现下图界面后,在右下角找到红色

    选择对象快捷键|对象全选的快捷键

    选择对象快捷键|对象全选的快捷键,,对象全选的快捷键第一种最常用最实用的Ctrl+鼠标多选单击选择一个文件夹或文件,然后左手按着“Ctrl”键

    ai对象对齐快捷键|ai智能对象快捷键

    ai对象对齐快捷键|ai智能对象快捷键,,1. ai智能对象快捷键找到“分割下方对象”,点击快捷键,然后同时按住“ctrl+1”,里面只要显示了,那就是可