You probably don't want a hierarchy like Bird
and Bat
arises from Animal
without fly()
method declared in lower class which are you delivering from. That way you just loose the point of unified hierarchy.
You can either do:
class Animal {
virtual bool canFly() { return false; }
virtual void fly() {throw Exception( "Sorry babe, I don't fly"); }
}
And override fly
in Bird
and Bat
.
This would cause you to have method fly()
implemented for dogs, cats which you probably don't want to. So maybe you could create new class Flyer
which would declare this method:
class Flyer : public Animal {
virtual void fly() = 0;
}
class Bat : public Flyer {}
class Bird : public Flyer {}
Which would be inconsistent with more detailed biological classification like Reptile
, Mammal
.
Another trick may be to propose method like move()
and dog would implement it as run()
and bird as fly()
, all with unified interface.
Another thing is, that I believe that it's valid question to ask whether dog can fly, so I think method like Dog.canFly()
should be implemented in your code, as a part of animal.
All this taken into account, I'd go with this:
// 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() {...}
}
And you just can do then (based on this answer I'm afraid that you'll have to use pointers for this):
if( Collection[i]->canFly()){
Flyer *thisBird = static_cast<Flyer*>(Collection[i]);
}
You could also derive Flyer
from Animal
and use virtual inheritance, but this is called "dreaded diamond" and it's not considered good practice, but worth reading.
As pointed out by Ricibob in comment, Flyer
should specify canFly()
, which will in simple example:
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'
But if you make Flyer
delivered from Animal
and Bird
part of classes Birds
and Flyer
:
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
Now canFly()
returns 1
, but code seems wrong to me.
At this point... You may either specify canFly()
manually for each subclass (or large groups), or deliver Birds
from Flyers
(which isn't right for example for Chicken
), or deliver new subclass:
class FlyingBrids : public Birds, public Flyer /* Flyer not delivered from Animal */ {
virtual bool canFly() const {return true;}
};
Note that Flyer
is still important because of Fly
delivered from Insect
.