C ++继承。对象调用超类方法而不是自己的方法?

时间:2011-11-22 02:02:30

标签: c++ polymorphism

所以我有2个班,

class Animal{
public:
    Animal(int age, int hairCount) {
        howOld = age;
        numOfHairs = hairCount;
    }

    void print(){
        cout << "Age: " << howOld << "\tNumber of Hairs: " << numOfHairs << endl;
    }

protected:
    int howOld;
    int numOfHairs;
};



class Bird: public Animal{
public:
    Bird(int age, int hairCount, bool fly) : Animal(age, hairCount) {
        canItFly = fly;
    }

    void print() {
        cout << "Age: " << howOld << "\tNumber of Hairs: " 
             << numOfHairs << "\tAbility to fly: " << canItFly << endl;
    }
protected:
    bool canItFly;
};

如果在主程序中,我有类似的东西:

#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<Animal> list;
    list.pushBack(Bird(5,10000,true));
    list.pushBack(Animal(14,1234567));

    for(int i = 0; i < list.size(); i++){
        list[i].print(); //Calls the super class for both outputs
    }
    return 0;
}

出于某种原因,我的代码(不是这样)在两种情况下调用超类的print方法。

4 个答案:

答案 0 :(得分:4)

您应该声明一个成员函数

void print()

是虚拟的,即

virtual void print()

除此之外,你应该创建一个指向Animal

的指针向量
vector<Animal *>

在main中使用new创建新对象。然后它将按预期工作。那说你的主要应该是这样的

vector<Animal *> list;
Animal *bird = new Bird(5,10000,true);
Animal *animal = new Animal(14,1234567);
list.push_back(bird);
list.push_back(animal);

如果您不再需要它们,请不要忘记删除鸟类和动物

delete bird;
delete animal;

根据Benjamin Lindley的建议,您可以选择使用其中一种智能指针类。

答案 1 :(得分:4)

您不能对静态类型的对象进行多态操作。您需要使用指针或引用。尝试vector<unique_ptr<Animal>>以避免内存管理问题。

答案 2 :(得分:4)

你刚遇到对象切片:)

http://en.wikipedia.org/wiki/Object_slicing

正如其他人所说,你不能静态地宣布一个动物阵列,因为它只会留出足够的空间来存放动物,像鸟类这样的东西会被切成碎片。

答案 3 :(得分:3)

多态性仅影响引用指针

Bird bibo;
Crocodile claus;

Animal & a1 = bibo, & a2 = claus;

a1.print();
a2.print();

只有一个通用的Animal a并不能让你访问任何多态行为,事实上它甚至可能没有意义:因为每个动物都是某种类型的具体动物,你的基类应该可能是抽象的。

现在容器怎么样?由于派生自基类的具体类可以具有可变大小,因此您无法直接将它们放入容器中。相反,您应该将指针指向基类到容器中。

选择的指针是std::unique_ptr<Animal>,它是轻量级的,是最简单的生命周期管理形式。它的工作原理如下:

#include <memory>
#include <vector>

typedef unique_ptr<Animal> AnimalPtr;
typedef std::vector<AnimalPtr> Zoo;

Zoo z;

z.push_back(AnimalPtr(new Bird));   // old-style
z.emplace_back(new Crocodile);      // new-style, better

最后,关于如何使Animal抽象的一个模糊的细节。我们可以声明print()是纯虚拟的。然而,我们也想要一个基础实现。我们可以做到这两点:

struct Animal
{
  virtual void print() const = 0;
  // ...
};
void Animal::print() const
{
  out << "Age: " << howOld << "\tNumber of Hairs: " << numOfHairs << endl;
}

struct Bird
{
  virtual void print() const
  {
    Animal::print();  //  call base function first
    cout << "Ability to fly: " << canItFly << endl;
  }
  // ...
};