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

C++: Polymorphism: Call Super Function

本文关键字:函数 调用 多态性 C++      更新时间:2023-10-16

我有一个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() {}

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

class Animal {
public:
    Animal();
    virtual ~Animal();
    virtual int talk() {return 0;}
};
您必须将

基方法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

你想要的称为动态调度,即根据要调用其成员函数的对象的类型选择要在运行时动态调用的函数。

在C++中,这是通过使用虚拟成员函数来实现的。若要使用它们,请将相应的成员函数声明为基类中的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;
}

(现场示例(

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

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