Получение функций унаследованных функций для вызова - PullRequest
3 голосов
/ 16 июня 2010

Допустим, у меня есть базовый класс Animal, от которого наследуется класс Cow, и класс Barn, содержащий вектор Animal, и, скажем, класс Animal имеет виртуальную функцию scream(), котораяCow переопределяет.

Со следующим кодом:

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;

public:
    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 */

и, наконец, 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);
}

Я получаю этот вывод:

aaaAAAAAAAAAAGHHHHHHHHHH!!! ahhh...

Как мне это кодировать, чтобы получить MOOooooOOOOOOOO!!! (и все остальноеклассы, наследующие Animal, хотят scream()) вместо?

Ответы [ 3 ]

12 голосов
/ 16 июня 2010

A std::vector<Animal> может содержать только Animal объектов, но не Cow объектов.

Вот что происходит, когда вы говорите barn.insertAnimal(Cow());:

  1. Временный объект типа Cow создается с помощью оценки Cow().
  2. Параметр animal создается из этой временной коровы, поскольку вы решили передать его по значению. Эта animal является копией Animal части временной коровы. Это называется объектная нарезка .
  3. Следующий элемент в векторе строится по копии из параметра animal. Теперь у вас уже есть одна корова и два дополнительных животных, но вы хотели только одну корову!
  4. Параметр animal уничтожен, потому что insertBarn возвращает.
  5. Временная корова уничтожена, поскольку оценка достигла точки с запятой в конце строки (точнее: оценка полного выражения завершена).

Какой урок здесь? Не передавайте животных по значению и не храните животных по значению. Полиморфизм времени исполнения требует определенного уровня косвенности. Вы, вероятно, хотите std::vector<Animal*> или std::vector<shared_ptr<Animal> > или boost::ptr_vector<Animal>.

2 голосов
/ 16 июня 2010

Вы делаете передачу по значению, поэтому Cow превращается в Animal.

Использование Animal * вместо этого работает, хотя это имеет утечки памяти:

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... */
}
2 голосов
/ 16 июня 2010

Небольшая модификация, которая хранит указатели на животных, должна помочь:

#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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...