容器类和调用具有继承的虚方法

时间:2016-04-16 16:34:17

标签: c++ inheritance virtual

我确定我错过了一些东西,但我真的无法在互联网上找到任何东西,为什么我的代码无法正常工作:

#include <stdio.h>
#include <iostream>
#include <fstream>
#include "string.h"
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
using namespace std;

class Animal {
private:
    char *name;
protected:
    enum { tele, empty } bendo;
public:
    Animal() {};
    Animal(const char *kname) : bendo(empty) {
        name = new char[strlen(kname) + 1];
        strcpy(name, kname);

    }
    const char *getname() { return name; }

    virtual ~Animal() {
        cout << "~" << name << endl;
        delete[] name;

    }

    virtual void print(std::ostream& os) const {
        os << "Animal.print" << std::endl;
    }

};

class Monkey : public Animal {
protected:
    static const char* SOUND;
public:
    Monkey(const char *kname) : Animal(kname) { }

    ~Monkey() { cout << SOUND << SOUND << " "; }

    virtual void print(std::ostream& os) const {
        os << "Monkey.print" << std::endl;
    }
};

const char* Monkey::SOUND = "Mak";

class Tiger : public Animal {
public:
    Tiger(const char *kname) : Animal(kname) { }

    virtual void print(std::ostream& os) const {
        os << "Tiger.print" << std::endl;
    }

};

class Cage{
    Animal* animals;
    unsigned int num;
public:
    Cage(){};
    ~Cage();
    void add(const Animal* a) {
        Animal* tmp = new Animal[num + 1];
        for (unsigned int i = 0; i < num; i++)
            tmp[i] = animals[i];
        tmp[num++] = *a;
        cout << "param: ";
        a->print(std::cout);
        cout << "in cage: ";
        tmp[num - 1].print(std::cout);
        animals = tmp;
    }
    void print(std::ostream& os) {
        for (unsigned int i = 0; i < num; i++){
            animals[i].print(os);
        }
    }

};


int main() {
    Animal *animal = new Animal("Animal");
    Animal *cicus = new Tiger("Cicus");
    Animal *csita = new Monkey("Csita");
    Animal *tarzan = new Monkey("AIAIAIAI");

    Cage* cage = new Cage;
    cout << "add animal" << endl;
    cage->add(animal);
    cout << endl << "add cicus" << endl;
    cage->add(cicus);
    cout << endl << "add csita" << endl;
    cage->add(csita);
    cout << endl << "add tarzan" << endl;
    cage->add(tarzan);

    cout << endl << "cage->print(cout);" << endl;
    cage->print(cout);
    cin.get();

}

基本上,我想在这里做些什么:

  1. 我有一个存储动物的课程(Cage)。
  2. 每只动物都有印刷(...)方法。
  3. 如果我打电话给cage.print(...),我希望它可以打电话给所有动物&#39; print(...)方法(Monkey.print(...),Tiger.print(...)等),但它总是调用Animal.print(...)方法。对于此代码,这是输出:

    add animal
    param: Animal.print
    in cage: Animal.print
    
    add cicus
    param: Tiger.print
    in cage: Animal.print
    
    add csita
    param: Monkey.print
    in cage: Animal.print
    
    add tarzan
    param: Monkey.print
    in cage: Animal.print
    
    cage->print(cout);
    Animal.print
    Animal.print
    Animal.print
    Animal.print
    
  4. 我在这里缺少什么?我做错了什么?


    好吧,正如@rodrigo所说,我遇到了所谓的对象切片&#39;错误,为了避免这种情况,我不得不将Animal* animals替换为Animal** animals,因此我不存储Animal对象,而是存储Animal POINTERS 。我只是在这里复制代码的重要部分,所以它只显示了这个特定问题的解决方案,所以要小心,它会错过其他东西(比如内存处理!)。

    class Cage{
        Animal** animals; // We need to store pointers!
        unsigned int num;
        unsigned int max;
    public:
        Cage(){
            num = 0;
            max = 10;
            animals = new Animal*[max];
        };
    
        void add(Animal* a) {
            /* Here I just 'optimized' a bit, 
    but of course the best would be to use linked list. */
            if (num == max) {
                max*=2;
                Animal** tmp = new Animal*[max];
                for (unsigned int i = 0; i < num; i++) {
                    tmp[i] = animals[i];
                }
                animals = tmp;
            }
            animals[num++] = a;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

问题是你的animals变量是Animal的数组,你需要一个指针或引用才能有多态行为。

您无法构建引用数组,因此您需要一个指针数组:Animal **animals

当您将Monkey复制到Animal时,您实际执行的操作是复制对象的动物部分并丢失猴子部分。这被称为拼接,并且几乎要避免。

PS:您应该使用std::stringstd::vector而不是管理自己的记忆。