# 虚函数与重写

URL: https://caijiao.org/cpp/oop/virtual
Source: docs/cpp/oop/virtual.md
Description: 本节介绍 C++ 中虚函数的概念与使用，虚函数如何在派生类中被重写，以及虚函数的动态绑定机制。

在 C++ 中，虚函数是实现多态的关键，它使得基类指针或引用可以调用派生类中重写的函数。虚函数与函数重写是面向对象编程中重要的概念，用于实现运行时的多态性。

## 虚函数的概念

虚函数是在基类中声明的函数，使用 `virtual` 关键字修饰。虚函数的作用是允许在派生类中重写该函数，并通过基类指针或引用来调用派生类版本的函数，从而实现动态绑定。

### 示例：虚函数的基本使用

```cpp
#include <iostream>
using namespace std;

class Base {
public:
    virtual void display() {
        cout << "Base class display function" << endl;
    }
};

class Derived : public Base {
public:
    void display() override {
        cout << "Derived class display function" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->display();  // 调用派生类的 display
    delete basePtr;
    return 0;
}
````

### 输出：

```
Derived class display function
```

在上面的例子中，`Base` 类的 `display` 函数被声明为虚函数，派生类 `Derived` 重写了该函数。当通过基类指针 `basePtr` 调用 `display` 函数时，实际调用的是派生类 `Derived` 的版本，而不是基类的版本。

## 函数重写

在派生类中重写基类的虚函数时，需要使用 `override` 关键字来标明该函数是重写的。虽然 `override` 关键字不是必须的，但它能帮助编译器进行检查，确保基类中有对应的虚函数被正确重写。

### 示例：函数重写

```cpp
#include <iostream>
using namespace std;

class Base {
public:
    virtual void display() {
        cout << "Base class display function" << endl;
    }
};

class Derived : public Base {
public:
    void display() override {  // 使用 override 明确声明重写
        cout << "Derived class display function" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->display();  // 调用派生类的 display
    delete basePtr;
    return 0;
}
```

## 虚函数的动态绑定

虚函数的调用是基于**动态绑定**的。也就是说，虚函数的调用会在运行时根据对象的实际类型进行确定，而不是在编译时。这种机制是实现多态的基础，使得通过基类指针或引用访问派生类函数成为可能。

### 示例：动态绑定

```cpp
#include <iostream>
using namespace std;

class Base {
public:
    virtual void speak() {
        cout << "Base class speaks" << endl;
    }
};

class Derived : public Base {
public:
    void speak() override {
        cout << "Derived class speaks" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->speak();  // 调用 Derived 类的 speak 函数
    delete basePtr;
    return 0;
}
```

### 输出：

```
Derived class speaks
```

虽然 `basePtr` 是 `Base` 类型，但它指向的是 `Derived` 类型的对象，因此通过 `basePtr` 调用 `speak` 函数时，实际上调用的是 `Derived` 类中的版本。

## 小结

* **虚函数**：在基类中声明，使用 `virtual` 关键字修饰，允许在派生类中重写该函数。
* **重写（Override）**：在派生类中重新定义基类的虚函数，并可使用 `override` 关键字进行标注。
* **动态绑定**：通过基类指针或引用调用虚函数时，编译器会在运行时决定调用哪个版本的函数，这就是虚函数实现多态的基础。

虚函数和重写是 C++ 中实现多态的核心机制，理解这些概念对面向对象编程的深入掌握至关重要。
