企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# C++ 虚函数 > 原文: [https://www.programiz.com/cpp-programming/virtual-functions](https://www.programiz.com/cpp-programming/virtual-functions) #### 在本文中,您将了解虚拟函数及其使用位置。 另外,您还将学习纯虚函数和抽象类。 虚函数是您希望在派生类中重新定义的基类中的成员函数。 在详细介绍之前,让我们先了解一下为什么首先需要虚拟函数。 * * * ## 一个例子 让我们假设,我们正在开发一个游戏(特别是武器)。 我们创建了`Weapon`类,并派生了两个类`Bomb`和`Gun`以加载相应武器的特性。 ```cpp #include <iostream> using namespace std; class Weapon { public: void loadFeatures() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void loadFeatures() { cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void loadFeatures() { cout << "Loading gun features.\n"; } }; int main() { Weapon *w = new Weapon; Bomb *b = new Bomb; Gun *g = new Gun; w->loadFeatures(); b->loadFeatures(); g->loadFeatures(); return 0; } ``` **输出** ```cpp Loading weapon features. Loading bomb features. Loading gun features. ``` 我们定义了`Weapon`,`Bomb`和`Gun`类的三个指针对象`w`,`b`和`g`。 并且,我们使用以下命令调用了每个对象的`loadFeatures()`成员函数: ```cpp w->loadFeatures(); b->loadFeatures(); g->loadFeatures(); ``` 完美的作品! 但是,我们的游戏项目开始变得越来越大。 并且,我们决定创建一个单独的`Loader`类来加载武器特性。 此类`Loader`类根据选择的武器来加载武器的其他函数。 ```cpp class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; ``` `loadFeatures()`加载特定武器的特性。 * * * ### 让我们尝试实现我们的`Loader`类 ```cpp #include <iostream> using namespace std; class Weapon { public: Weapon() { cout << "Loading weapon features.\n"; } void features() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void features() { this->Weapon::features(); cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void features() { this->Weapon::features(); cout << "Loading gun features.\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; } ``` **输出** ```cpp Loading weapon features. Loading weapon features. Loading weapon features. Loading weapon features. ``` 我们的实现似乎是正确的。 但是,武器特性被加载了 4 次。 为什么? 最初,武器对象`w`指向`Bomb`类的`b`对象。 并且,我们尝试使用指向`Loader`类的指针的`l`对象将其传递给`loadFeatures()`函数来加载`Bomb`对象的特性。 同样,我们尝试加载`Gun`对象的特性。 但是,`Loader`类的`loadFeatures()`函数将指向`Weapon`类的对象的指针作为参数: ```cpp void loadFeatures(Weapon *weapon) ``` 这就是武器特性被加载 4 次的原因。 要解决此问题,我们需要使用`virtual`关键字使基类(`Weapon`类)的特性虚拟化。 ```cpp class Weapon { public: virtual void features() { cout << "Loading weapon features.\n"; } }; ``` * * * ## 示例:使用虚函数解决问题 ```cpp #include <iostream> using namespace std; class Weapon { public: virtual void features() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void features() { this->Weapon::features(); cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void features() { this->Weapon::features(); cout << "Loading gun features.\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; } ``` **输出** ```cpp Loading weapon features. Loading bomb features. Loading weapon features. Loading gun features. ``` 另外,请注意,`l->loadFeatures(w)`函数根据`l`对象所指向的对象调用不同类的函数。 使用虚函数使我们的代码不仅更清晰,而且更加灵活。 在以上程序中,武器特性被打印了两次。 我们建议您在上述程序上添加其他代码,以仅加载一次武器特性。 如果我们想添加另一种武器(比如说刀),我们可以轻松地添加和加载其特性。 **怎么样**? ```cpp class Knife : public Weapon { public: void features() { this-<Weapon::features(); cout >> "Loading knife features.\n"; } }; ``` 并且,在`main()`函数中。 ```cpp Knife k; w = &k; l->loadFeatures(w); ``` 值得注意的是,我们没有更改`Loader`类中的任何内容来加载刀的特征。 * * * ## C++ 抽象类和纯虚函数 面向对象编程的目的是将一个复杂的问题分成几个小集合。 这有助于有效理解和处理问题。 有时,仅在更好地可视化问题的情况下才需要使用继承。 在 C++ 中,您可以创建一个无法实例化的抽象类(您不能创建该类的对象)。 但是,您可以从中派生一个类并实例化派生类的对象。 抽象类是无法实例化的基类。 包含纯虚函数的类称为抽象类。 * * * ## 纯虚函数 声明以`= 0`结尾的虚函数称为纯虚函数。 例如, ```cpp class Weapon { public: virtual void features() = 0; }; ``` 在这里,纯虚函数是 ```cpp virtual void features() = 0 ``` 并且,类`Weapon`是抽象类。 * * * ## 示例:抽象类和纯虚函数 ```cpp #include <iostream> using namespace std; // Abstract class class Shape { protected: float l; public: void getData() { cin >> l; } // virtual Function virtual float calculateArea() = 0; }; class Square : public Shape { public: float calculateArea() { return l*l; } }; class Circle : public Shape { public: float calculateArea() { return 3.14*l*l; } }; int main() { Square s; Circle c; cout << "Enter length to calculate the area of a square: "; s.getData(); cout<<"Area of square: " << s.calculateArea(); cout<<"\nEnter radius to calculate the area of a circle: "; c.getData(); cout << "Area of circle: " << c.calculateArea(); return 0; } ``` **输出** ```cpp Enter length to calculate the area of a square: 4 Area of square: 16 Enter radius to calculate the area of a circle: 5 Area of circle: 78.5 ``` 在此程序中,在`Shape`类中定义了纯虚函数`virtual float area() = 0;`。 需要注意的一件事是,您应该在派生类中覆盖基类的纯虚函数。 如果覆盖失败,则派生类也将成为抽象类。