C++ 虚函数

C++ 虚函数

虚函数是基类中可以在派生类中被重写的成员函数。

虚函数是 C++ 多态性 的一个关键部分。它们允许不同的对象对同一个函数调用做出不同的响应。

为什么使用虚函数?

没有 virtual,C++ 会根据指针类型来决定调用哪个函数,而不是实际的对象类型。

有了 virtual,它会检查指针实际指向的对象。

或者更简单地说:

  • 没有 virtual:即使对象来自子类,基类函数也会运行。
  • 有了 virtual:子类的版本会运行,如您所期望的那样。

没有虚函数的情况

示例(无 virtual 关键字)

class Animal {
  public:
    void sound() {
      cout << "动物声音\n";
    }
};

class Dog : public Animal {
  public:
    void sound() {
      cout << "狗吠叫\n";
    }
};

int main() {
  Animal* a;  // 声明一个指向基类 (Animal) 的指针
  Dog d;  // 创建一个派生类 (Dog) 的对象
  a = &d;  // 将基类指针指向 Dog 对象
  a->sound(); // 使用指针调用 sound() 函数。由于 sound() 不是虚函数,这会调用 Animal 的版本
  return 0;
}

亲自试一试

尽管 a 指向一个 Dog,它仍然调用 Animal::sound(),因为该函数不是虚函数。

有虚函数的情况

示例(使用 virtual 关键字)

class Animal {
  public:
    virtual void sound() {
      cout << "动物声音\n";
    }
};

class Dog : public Animal {
  public:
    void sound() override {
      cout << "狗吠叫\n";
    }
};

int main() {
  Animal* a;
  Dog d;
  a = &d;
  a->sound(); // 输出:狗吠叫
  return 0;
}

亲自试一试

现在它按预期工作了!因为 sound() 是虚函数,调用使用了实际对象的函数,而不仅仅是指针类型。

  • 仅在基类中使用 virtual
  • 在派生类中使用 override(可选,但推荐)以提高清晰度

C++ 中的 -> 运算符

您可能想知道为什么我们在上面的例子中使用了 ->

-> 运算符用于通过指针访问成员(如函数或变量)。

它是 (*pointer).member 的快捷方式:

Animal* a = new Animal();
a->sound(); // 等同于 (*a).sound();

提示:如果您使用的是指向对象的指针,请使用 -> 来访问其成员。