1

我有一些不同类型的对象Zoo,它们都有一个成员变量Collection = vector<Animal>。我有一个动物园实例,其中所有元素都是动物,一个是所有元素Birds,一个是所有元素Bats。两者BirdsBats来自动物。

我希望有一种方法fly()可以调用所有的鸟类和蝙蝠,但我不确定最好的方法。我应该在我的鸟类/蝙蝠动物园循环时施放吗?像这样:

Bird thisBird = static_cast<Bird>(Collection[i]);
thisBird.fly();

...或者我可以在 Animal 上以某种方式拥有一个虚拟函数,它只在派生自它的类上实现?

想法,以及为什么它们是“好代码”的理由,欢迎!

4

3 回答 3

1

哦,是的,Animal可以有一个虚函数:

virtual void move(){}
virtual void fly(){}

当你命令一只狗飞行时,它什么也不做。当你命令一只鸟移动时,它fly()也会叫。

正确定义fly()会飞的动物, Colection[i]->fly()只会做正确的事。这样你的代码就会很简单。

但要做到这一点,您的集合必须收集指向动物的指针,而不仅仅是 Animal 对象。例如:

#include <vector>
#include <memory>
#include <iostream>  
using namespace std;
struct Animal{virtual void fly(){}};
struct Bird:public Animal{void fly(){cout<<"fly\n";}};
int main()
{
  vector<unique_ptr<Animal>> Colection(1);
  Colection[0].reset( new Bird ); 
  Colection.push_back(unique_ptr<Animal>(new Bird) );
  Colection.push_back(unique_ptr<Animal>(new Animal) );
  Colection[0]->fly(); 
  Colection[1]->fly(); 
  Colection[2]->fly();   
}

阅读其他答案,我可以建议您实施类似

struct Animal    {virtual bool fly(){return false;     }};
struct Bird:public Animal{bool fly(){cout<<"fly\n";return true;}};

而且您不需要单独的 canFly。

于 2013-04-12T12:17:21.380 回答
1

并非所有动物都能飞,因此没有必要为了通用目的而尝试执行特定行为(即所有动物之间不常见)。如果您有动物类(或其派生类)的集合,其目的是允许它们执行共同行为(每个派生类以不同方式实现)。

您可以实现一个FlyAble接口(即抽象类)并仅由真正会飞的动物扩展它。不仅仅是将它们保存在为这些类型的动物指定的另一个集合中(即< FlyAble>)。

于 2013-04-12T11:33:03.757 回答
1

你可能不想要一个层次结构,就像在你交付的低类中没有声明的方法Bird那样产生Bat。这样你就失去了统一层次结构的意义。Animalfly()

你可以这样做:

class Animal {
    virtual bool canFly() { return false; }
    virtual void fly() {throw Exception( "Sorry babe, I don't fly"); }
}

并覆盖fly和。BirdBat

这将导致您为fly()您可能不想要的狗、猫实现方法。所以也许你可以创建一个新的类Flyer来声明这个方法:

class Flyer : public Animal {
    virtual void fly() = 0;
}

class Bat : public Flyer {}
class Bird : public Flyer {}

这将与更详细的生物学分类不一致,例如ReptileMammal

另一个技巧可能是提出方法 likemove()和 dog 会实现它 asrun()和 bird as fly(),都具有统一的接口。

另一件事是,我认为问狗是否会飞是一个有效的问题,所以我认为 Dog.canFly()应该在你的代码中实现类似的方法,作为动物的一部分。

考虑到所有这些,我会这样做:

// Your base animal
class Animal {
    virtual bool canFly() {return false;}
};

// Any animal that could fly, just abstract class
class Flyer {
    virtual void fly() = 0;
}

// Ants, flies etc.; real biological hierarchy
class Insect : public Animal {}
class Mammals : public Animals {}
class Birds : public Animals {}

// And now flying bird :
class Bird : public Birds, public Flyer {
    virtual bool canFly() {return true; }
    virtual void fly() {...}
}

// And flying insect
class Fly : public Insect, public Flyer {
    virtual bool canFly() {return true; }
    virtual void fly() {...}
}

然后您就可以这样做(基于此答案,恐怕您必须为此使用指针):

if( Collection[i]->canFly()){
    Flyer *thisBird = static_cast<Flyer*>(Collection[i]);
}

您也可以从虚拟继承派生FlyerAnimal使用虚拟继承,但这被称为“可怕的钻石”,它不被认为是好的做法,但值得一读。


正如Ricibob在评论中指出的那样,Flyer应该指定canFly(),这将在简单的示例中:

class Flyer {
public:
    virtual bool canFly() const {return true;}
    virtual void fly() {cout << "Flying" << endl; }
};

Bird b;
cout << "Can fly: " << b.canFly() << endl;
// Error    1   error C2385: ambiguous access of 'canFly'

但是,如果您从课程的一部分中Flyer交付Animal并且:BirdBirdsFlyer

class Animal {
public:
    virtual bool canFly() const {return false;}
};

class Flyer : virtual Animal {
public:
    virtual bool canFly() const {return true;}
    virtual void fly() {cout << "Flying" << endl; }
};

class Bird : virtual public Birds, virtual public Flyer {

}; 

// Warning  1   warning C4250: 'Bird' : inherits 'Flyer::Flyer::canFly' via dominance

现在canFly()返回1,但代码对我来说似乎是错误的。

此时......您可以canFly()为每个子类(或大型组)手动指定,或者BirdsFlyers(例如对于 不正确Chicken)交付,或者交付新的子类:

class FlyingBrids : public Birds, public Flyer /* Flyer not delivered from Animal */ {
    virtual bool canFly() const {return true;}
};

请注意,这Flyer仍然很重要,因为FlyInsect.

于 2013-04-12T11:41:44.197 回答