Search code examples
c++virtualbase-class

best way of accessing method on derived class C++


I have some different objects all of type Zoo, which have a member variable Collection = vector<Animal>. I have one instance of zoo where all the elements are Animals, one where all the elements are Birds, and one where all the elements are Bats. Both Birds and Bats derive from Animals.

I want there to be a method fly() that I can call on all the birds and bats, but I'm not sure the best way of doing this. Should I just cast when looping through my bird/bat zoo? Like this:

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

... or could I somehow have a virtual function on Animal, that is only implemented on the classes that derive from it?

Ideas, and justifications for why they're 'good code', welcome!


Solution

  • Oh, yes, Animal could have a virtual function:

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

    When you order a dog to fly it do nothing. When you order a bird to move it could call fly() too.

    Define fly() correctly for the animal who fly, and just Colection[i]->fly() will do the correct thing. This way your code will be simple.

    But to do it your collection have to collect pointer to the animals, not just Animal objects. For example:

    #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();   
    }
    

    Reading other answer I can recommend you to implement something like

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

    And you dont need a separate canFly.