最好的方法访问方法的派生类c++

best way of accessing method on derived class C++

本文关键字:方法 c++ 派生 访问      更新时间:2023-10-16

我有一些类型都是Zoo的不同对象,它们有一个成员变量Collection = vector<Animal>。我有一个动物园的例子,所有的元素都是动物,一个是所有的元素都是Birds,一个是所有的元素都是BatsBirdsBats都来源于Animals.

我希望有一个方法fly(),我可以调用所有的鸟类和蝙蝠,但我不确定这样做的最好方法。当我在我的鸟/蝙蝠动物园里循环时,我是否应该直接投射?这样的:

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

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

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

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

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

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

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

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

#include <vector>
#include <memory>
#include <iostream>  
using namespace std;
struct Animal{virtual void fly(){}};
struct Bird:public Animal{void fly(){cout<<"flyn";}};
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<<"flyn";return true;}};

你不需要单独的canFly

不是所有的动物都会飞,所以没有必要为了通用的目的而尝试执行特定的行为(即所有动物之间不常见的行为)。如果你有一个Animal类(或它们的派生类)的集合,它的目的是允许它们做一个共同的行为(由每个派生类实现不同)。

你可以实现一个FlyAble接口(即抽象类),并且只对真正会飞的动物进行扩展。然后把它们保存在另一个为这类动物指定的收藏中(即<FlyAble>)。

你可能不希望像BirdBat这样的层次结构产生于Animal,而没有在较低的类中声明fly()方法。这样你就失去了统一的层次结构。

你可以做:

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

BirdBat中重写fly

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

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

这将与Reptile, Mammal等更详细的生物分类不一致。

另一个技巧可能是提出像move()这样的方法,dog将其实现为run(), bird将其实现为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]);
}

您也可以从Animal派生Flyer并使用虚拟继承,但这被称为"可怕的钻石",这不是一个好的实践,但值得一读。


正如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'

但是如果您将FlyerAnimalBird交付给BirdsFlyer类:

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(),或者从Flyers交付Birds(例如Chicken就不正确),或者交付新的子类:

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

注意Flyer仍然很重要,因为Fly是从Insect传递过来的。