在C ++中has-a关系中的接口是否有很好的替代方法

温德拉

我在GUI设计中遇到了一个OOP问题,但让我以动物为例进行说明。让我们进行以下设置:

  • 有一个基类动物
  • 任何派生类都可以拥有-牙齿
  • 每个有牙齿的动物都可以Bite()<=>没有牙齿的动物都不能Bite()
  • 每个动物Bite()都采用相同的方式(在Teeth类中有默认实现)

对于动物has-a牙齿来说这是很自然的,但是现在我需要诸如has-a关系的接口例如,如果我有一个动物矢量,那么我如何制作每个Bite()?

std::vector<Animal *> animals;
animals.push_back(new dog());
animals.push_back(new fly());
animals.push_back(new cat());

void Unleash_the_hounds(std::vector<Animal *> animals) 
{
    //bite if you can!
}

我想出了几种解决方案,但似乎没有一种非常合适:

1.)每个带有牙齿的类也实现接口IBiting。但是,此解决方案引入了很多代码重复,我将需要在每个类中“实现” Bite():

class Cat : public Animal, public IBiting {
    Teeth teeth;
public:
    virtual void Bite() { teeth.Bite(); }
}

2.)给每只动物牙齿,但只允许一些使用它们。注意:语法可能是错误的-仅用于说明

class Animal{
    static cosnt bool canBite = false;
    Teeth teeth;
public:
    void Bite() { this->canBite ? teeth.Bite() : return; }
}

class Cat {
    static cosnt bool canBite = true;
}

3.)更多继承-创建类BitingAnimal并派生它。好吧,这可能行得通,但是如果我需要派生(非)飞行动物,其中一些有牙齿,该怎么办?

class Animal{}
class BitingAnimal : public Animal {
    Teeth teeth;
}

并用作BitingAnimal.teeth.Bite()

4.)多重继承。通常不鼓励这样做,并且在大多数语言中是不可能做到的,此外,让Cat成为牙齿也不合逻辑。

class Cat : public Animal, public Teeth {
}

5.)可以咬的类的枚举-仅凭其声音感到奇怪。


还是我只是过于复杂而错过了重要的事情?

菲尔达

1)界面不错,您可以通过以下方式添加默认实现:

class IBiting { public virtual void bite() = 0 };
class HasTeeth, public IBiting { Teeth teeth; public:
    virtual void bite() override { teeth.bite(); } };

for(Animal* a: animals) {
    IBiting* it = dynamic_cast<IBiting*>(a);
    if(it) it->bite(); }

1b)...您也可以完全删除该界面并仅使用HasTeeth

class HasTeeth { Teeth teeth; public:
    void bite() { teeth.bite(); } };

for(Animal* a: animals) {
    HasTeeth* it = dynamic_cast<HasTeeth*>(a);
    if(it) it->bite(); }

2)Animal如果您不想使用RTTI /,可以使用Bloating dynamic_cast您可以virtual void bite()在Animal上使用空实现,然后稍后将其覆盖(添加Teeth)。如果您坚持不使用RTTI,则不需要那么多的编码,但是如果可以使用dynamic_cast,为什么不使用它呢?

编辑:沃恩·卡托Vaughn Cato的答案非常适合此-虚拟/抽象teethPtr()(或getTeeth())在Animal中具有类似的快捷方式biteIfYouCan()对嵌入式世界(微芯片)有利,但对PC来说,我还是更喜欢dynamic_cast

3)虚拟继承可以帮助我们解决BitingAnimalvs FlyingAnimal

class BitingAnimal: public virtual Animal {
Teeth teeth; public void bite() { teeth.bite(); } };
class FlyingAnimal: public virtual Animal {
Wings wings; public void fly() { wings.fly(); } };
class FlyingBitingAnimal: /*public virtual Animal, */
public FlyingAnimal, public BitingAnimal {};

4)加入AnimalTeeth没有感觉,除非你完全删除Teeth,取而代之的是HasTeethCanBite然后变成我的1b

5)该枚举是2型腹胀动物的另一个版本。不好。但这使我想到了不使用dynamic_cast的替代方法:您可以通过可以告诉您功能(枚举或动物标志bool can_bite来模仿它,这种转换是安全的。然后,您可以使用多重/虚拟继承来模拟dynamic_cast(首先检查功能,然后投射)。

编辑: 沃恩·卡托Vaughn Cato)也teethPtr()与此匹配(向我展示如果您有牙齿可以咬的牙齿),并且不需要石膏。


回答评论:

简而言之:尝试命名功能(能力,做某事的能力,提供某事的能力)。

长答案:您需要TeethHasTeeth还是单身CanBite您的第四个解决方案在原则上还不错,但是在命名以及其他可能性上也不错。所有这些都是假设的。接口在其他语言中(单继承+接口)HasTeeth众所周知的,类似于C#IListSourceIList GetList()andbool ContainsList(用于擦除),其中bite()不直接存在,但可以通过扩展方法添加:

static IEnumerator GetEnumerator(this IListSource it) {
    if(!it.ContainsList) yield break;
    foreach(object o in it.GetList()) yield return o; }

在这里您可以看到,使用C#扩展方法与使用C ++多重继承可以达到相同的目的。该名称是-一个形式- SourceOf您可以与我们共享您的GUI的真实姓名吗?

来自C ++的示例是iostream = istream + ostream,具有从ios的虚拟继承。再次是-命名。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

C#是否有很好的方法迭代一个范围中的每个整数(减去1)?

Java中的gettext _()方法有很好的替代方法吗?

在C#中是否有Java标记的等效中断或替代方法

对于Objective-C中的这种基本计算,是否有最佳的替代方法?

C# LINQ 中的`let` 关键字是否有强制替代方法?

在C ++中,有没有'system()'命令的替代方法?

在Objective-C中是否有类似Java Comparable的接口?

MySQL中是否有CONCAT()的替代方法?

在C ++中引发异常的替代方法有哪些

是否可以在接口的派生类中仅使用C#中的该接口的某些方法?

与C#中的方法的接口?

C#中的替代内联接口实现

html/javascript 中的 onloadend 有很好的替代品吗?

在C ++ 11或更高版本中,是否可以通过lambda实现单方法的纯虚拟C ++接口?

是否有任何类似于C#中的NameValueCollection集合的替代项

在clang和gcc中,是否存在可视C ++ __declspec(属性声明属性)的替代方法?

在C ++中,是否存在cout的替代方法,其行为类似于qDebug?

在Collection接口方法中,boolean equals(Object obj)是否有任何Object obj符合参数的资格,或者只有Collection c符合参数的资格?

是否可以使接口方法返回带有C#中通用类型参数的另一个方法的类型?

C#中是否有Java中的equalsIgnoreCase之类的方法

接口是否可以有效替代Java 8中的实用程序类?

有没有替代 C 中数组的范围初始化的方法?

在此代码中是否有使用“this”的替代方法?

MSTest中是否有非静态的ClassInitialize替代方法?

Fortran 2003-2008中是否有GETCWD()的替代方法

protobuf 中是否有替代 flatbuffers 结构的方法?

Google Apps 脚本中是否有 toFixed() 的替代方法?

VBA中是否有for-if循环的替代方法?

在Gmail中是否有支持“背景位置”的替代方法?