容器 class 并通过继承调用虚方法

Container class and calling virtual methods with inheritance

我确定我遗漏了一些东西,但我真的无法在互联网上找到任何我的代码无法按预期工作的原因:

#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. 我有一个 class(笼子)用来存放动物。
  2. 每种动物都有一个 print(...) 方法。
  3. 如果我调用 cage.print(...),我希望它调用所有动物的 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
    

我在这里错过了什么?我做错了什么?


解决方案
好吧,正如@rodrigo 所说,我 运行 进入了所谓的 'object slicing' 错误,为了避免这种情况,我不得不将 Animal* animals 替换为 Animal** animals,所以我存储的不是 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;
    }
}

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

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

例如,当您将 Monkey 复制到 Animal 时,您实际上所做的是复制对象的动物部分并丢失猴子部分。这就是所谓的拼接,几乎总是要避免的。

PS:你应该使用std::stringstd::vector而不是管理你自己的内存。