C ++:多态:调用超级函数

时间:2016-01-30 19:57:47

标签: c++ polymorphism

我有一个Animal数组。

Animal默认为"Animal"

我也Cat延伸Animal并改为"Meow"

我也Dog延伸Animal并改为"Woof"

我想要的是什么:

Animal* a[2];
a[0] = new Cat();
a[1] = new Dog();
a[0]->talk(); //Meow
a[1]->talk(); //Woof

会发生什么:

Animal* a[2];
a[0] = new Cat();
a[1] = new Dog();
a[0]->talk(); //Animal
a[1]->talk(); //Animal

//头

class Animal {
public:
    Animal();
    ~Animal();
    int talk() {return 0;}
};

class Cat : public  Animal {
public:
    Cat();
    ~Cat();
    int talk() {return 1;}
};

class Dog : public Animal {
public:
    Dog();
    ~Dog();
    int talk() {return 2;}
};

//。CPP

void letsHear(Animal *a) {
    _LOG_INFO() << a->talk();
}

int main(){
    Animal* a[2];
    a[0] = (Animal *)new Cat();
    a[1] = (Animal *)new Dog();

    letsHear((Animal *)new Cat()); //0
    letsHear((Animal *)new Dog()); //0
    letsHear(new Animal()); //0
    letsHear(a[0]); //0
    letsHear(a[1]); //0
    return 0;
}
Cat::Cat() {}
Cat::~Cat(){}
Dog::Dog() {}
Dog::~Dog() {}
Animal::Animal() {}
Animal::~Animal() {}

3 个答案:

答案 0 :(得分:3)

要在C ++中获得多态行为,必须将函数声明为virtual。在任何多态基类中使析构函数都是虚拟的是个好主意:

class Animal {
public:
    Animal();
    virtual ~Animal();
    virtual int talk() {return 0;}
};

答案 1 :(得分:1)

您必须将基本方法talk()声明为virtual函数。 看一下这个例子。

class Animal {
public:
    virtual void talk() {
        cout << "Animal" << endl;
    }
};

class Cat : public Animal {
public:
    void talk() {
        cout << "Meow" << endl;
    }
};

class Dog : public Animal {
public:
    void talk() {
        cout << "Woof" << endl;
    }
};

之后,您可以像在您的示例中一样调用您的方法。

Animal *a[2];
a[0] = new Cat();
a[1] = new Dog();
a[0]->talk(); //Meow
a[1]->talk(); //Woof

答案 2 :(得分:1)

您想要的是dynamic dispatch,即根据您要调用其成员函数的对象的类型,选择在运行时动态调用的函数。

在C ++中,这是通过使用virtual member functions来完成的。要使用它们,请在基类中将相应的成员函数声明为virtual

#include <iostream>
#include <array>
#include <memory>
using namespace std;

struct Animal {
    virtual void speak() const {
        cout << "Animal" << endl;
    }
    virtual ~Animal() {} // Better add this, too!
};
struct Cat : public Animal {
    virtual void speak() const override {
        cout << "Meow" << endl;
    }
};
struct Dog : public Animal {
    virtual void speak() const override {
        cout << "Wuff" << endl;
    }
};

int main() {
    array<unique_ptr<Animal>, 3> animals;
    animals[0] = make_unique<Cat>();
    animals[1] = make_unique<Dog>();
    animals[2] = make_unique<Animal>();
    for (auto const & a : animals) {
        a->speak();
    }
    return 0;
}

(Live example)

如果(任何)派生类添加成员字段,并且这些类的任何实例的所有权掌握在指向基类型的某些指针的手中(如我的示例所示),那么您应该遵循aschelper的建议并制作基础析构函数virtual。否则你会得到内存泄漏。

您可以看到我在我的代码中使用标准库中的一些概念,例如unique_ptrarray以及for循环中的类型推断。应该在适当的时候使用这些,在大多数情况下使用原始数组/指针不再需要,并且很容易导致内存管理错误。