开发者

Getting functions of inherited functions to be called

开发者 https://www.devze.com 2023-01-03 09:38 出处:网络
Let\'s say I have a base class Animal from which a class Cow inherits, and a Barn class containing an Animal vector, and let\'s say the Animal class has a virtual function scream(), which Cow override

Let's say I have a base class Animal from which a class Cow inherits, and a Barn class containing an Animal vector, and let's say the Animal class has a virtual function scream(), which Cow overrides.

With the following code:

Animal.h

#ifndef _ANIMAL_H
#define _ANIMAL_H
#include <iostream>
using namespace std;

class Animal {
public:
    Animal() {};
    virtual void scream() {cout << "aaaAAAAAAAAAAGHHHHHHHHHH!!! ahhh..." << endl;}
};

#endif  /* _ANIMAL_H */

Cow.h

#ifndef _COW_H
#define _COW_H

#include "Animal.h"

class Cow: public Animal {
public:
    Cow() {}
    void scream() {cout << "MOOooooOOOOOOOO!!!" << endl;}
};

#endif  /* _COW_H */

Barn.h

#ifndef _BARN_H
#define _BARN_H

#include "Animal.h"
#include <vector>

class Barn {
    std::vector<Animal> animals;

publi开发者_如何学运维c:
    Barn() {}
    void insertAnimal(Animal animal) {animals.push_back(animal);}
    void tortureAnimals() {
        for(int a = 0; a < animals.size(); a++)
            animals[a].scream();
    }
};

#endif  /* _BARN_H */

and finally main.cpp

#include <stdlib.h>
#include "Barn.h"
#include "Cow.h"
#include "Chicken.h"

/*
 * 
 */
int main(int argc, char** argv) {
    Barn barn;
    barn.insertAnimal(Cow());
    barn.tortureAnimals();
    return (EXIT_SUCCESS);
}

I get this output:

aaaAAAAAAAAAAGHHHHHHHHHH!!! ahhh...

How should I code this to get MOOooooOOOOOOOO!!! (and whatever other classes inheriting Animal wants scream() to be) instead?


A std::vector<Animal> can only contain Animal objects, not Cow objects.

Here's what happens when you say barn.insertAnimal(Cow());:

  1. A temporary object of type Cow is created by the evaluation of Cow().
  2. The parameter animal is copy-constructed from that temporary cow since you chose to pass it by value. This animal is a copy of the Animal-part of the temporary cow. This is called object-slicing.
  3. The next element in the vector is copy-constructed from the parameter animal. Now you already have one cow and two additional animals, but you only wanted one cow!
  4. The parameter animal is destroyed because insertBarn returns.
  5. The temporary cow is destroyed because evaluation has reached the semicolon at the end of the line (to be more precise: evaluation of the full-expression has completed).

What is the lesson here? Don't pass animals by value, and don't store animals by value. Runtime polymorphism requires a level of indirection. You probably want a std::vector<Animal*> or std::vector<shared_ptr<Animal> > or boost::ptr_vector<Animal>.


A slight modification that stores pointers to animals should help:

#ifndef _BARN_H
#define _BARN_H

#include "Animal.h"
#include <vector>

class Barn {
    std::vector<Animal *> animals;

public:
    Barn() {}
    void insertAnimal(Animal *animal) {animals.push_back(animal);}
    void tortureAnimals() {
        for(int a = 0; a < animals.size(); a++)
            animals[a]->scream();
    }
};


int main(int argc, char** argv) {
    Barn barn;
    barn.insertAnimal(new Cow());
    barn.tortureAnimals();

    // should clean up barn contents here...

    return (EXIT_SUCCESS);
}


You're doing pass-by-value, so Cow is being made into Animal.

Using Animal * instead works, though this has memory leaks:

class Barn {
    std::vector<Animal *> animals;

    void insertAnimal(Animal *animal) {animals.push_back(animal);}

    void tortureAnimals() {
        for(int a = 0; a < animals.size(); a++)
            animals[a]->scream();
    }
};

int main(int argc, char** argv) {
    Barn barn;
    Cow *c = new Cow();
    barn.insertAnimal(c);
    barn.tortureAnimals();
    /* delete them here... */
}
0

精彩评论

暂无评论...
验证码 换一张
取 消