📜  C++ |虚函数|问题5(1)

📅  最后修改于: 2023-12-03 15:29:52.071000             🧑  作者: Mango

C++ | 虚函数 | 问题5

在 C++ 中,虚函数是一种非常有用的概念。它们可以帮助我们实现多态性,即让子类对象表现出与父类不同的行为。但是,在使用虚函数时,我们可能会遇到问题。本文将介绍 C++ 中虚函数可能遇到的一些问题以及解决方法。

问题描述

基类 Animal 有一个虚函数 speak(),两个子类 Cat 和 Dog 分别重写这个函数。现在我们用一个指向 Animal 的指针变量调用 speak(),但是它调用的是基类 Animal 的 speak() 函数,而不是子类的。为什么会出现这种情况,该如何解决呢?

#include <iostream>

class Animal {
public:
    virtual void speak() {
        std::cout << "Animal speak." << std::endl;
    }
};

class Cat : public Animal {
public:
    void speak() {
        std::cout << "Cat speak." << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        std::cout << "Dog speak." << std::endl;
    }
};

int main() {
    Animal* a = new Cat();
    a->speak(); // 输出 "Animal speak."
    return 0;
}
问题原因

问题在于,当使用一个指向派生类对象的基类指针或引用调用虚函数时,该指针或引用不知道它们指向的到底是基类还是派生类,因此它们只会调用基类的虚函数。

在上面的代码中,Animal* a = new Cat(); 创建了一个 Cat 的对象,并且使用基类 Animal 的指针 a 指向该对象。调用 a->speak() 时,由于 speak() 是虚函数,编译器将自动解析出适当的函数调用。但是,由于 a 是基类 Animal 的指针,编译器只会找到基类的 speak() 函数。

解决方法

要解决这个问题,我们需要在派生类的函数前加上 virtual 关键字。这样,当使用基类指针或引用调用函数时,编译器会检查实际指向的对象的类型,并选择正确的函数。

class Animal {
public:
    virtual void speak() {
        std::cout << "Animal speak." << std::endl;
    }
};

class Cat : public Animal {
public:
    virtual void speak() {
        std::cout << "Cat speak." << std::endl;
    }
};

class Dog : public Animal {
public:
    virtual void speak() {
        std::cout << "Dog speak." << std::endl;
    }
};

int main() {
    Animal* a = new Cat();
    a->speak(); // 输出 "Cat speak."
    return 0;
}
总结

虚函数是实现多态性的重要工具,但在使用时可能会出现问题。当使用基类指针或引用调用虚函数时,如果没有在派生类中将函数声明为虚函数,可能会调用基类的函数。为了避免这个问题,必须确保在派生类中将函数声明为虚函数。