术语"Polymorphism"是"poly" +"morphs"的组合,表示多种形式。这是一个希腊词。在面向对象的编程中,我们使用3个主要概念:继承,封装和多态。
C++中有两种类型的多态性:

- 编译时多态性 - 通过匹配参数的类型和数量来调用重载函数。该信息在编译时可用,因此,编译器在编译时选择适当的函数。它是通过函数重载和运算符重载来实现的,也称为静态绑定或早期绑定。现在,让我们考虑一下函数名称和原型相同的情况。
class A // 基类声明。 { int a; public: void display() { cout<< "Class A "; } x}; class B : public A // 派生类声明。 { int b; public: void display() { cout<<"Class B"; } };
在上述情况下,基类和派生类中的display()函数原型相同。因此,不能应用静态绑定。如果在运行时选择了适当的函数,这称为运行时多态性。
- 运行时多态性 - 运行时多态性是在运行时而不是编译时调用对象的方法时实现的。它是通过方法重写(也称为动态绑定或后期绑定)来实现的。
编译Vs运行多态性。
| 编译时多态性 | 运行时多态性 |
|---|---|
| 在编译时就知道要调用的函数。 | 要在运行时知道要调用的函数。 |
| 也称为重载,早期绑定和静态绑定。 | 也称为覆盖,动态绑定和后期绑定。 |
| 重载是一种编译时多态,其中多个方法具有相同的名称,但参数数量或参数类型不同。 | 重载是一种运行时多态,其中多个方法具有相同的名称,参数数量和参数类型。 |
| 通过函数重载和运算符重载来实现。 | 它是通过虚函数和指针实现的。 |
| 它提供了编译时所知道的快速执行。 | 它提供了缓慢的执行速度在运行时已知。 |
| 它的灵活性较差,因为主要是所有事物在编译时执行。 | 它更灵活,因为所有事情都在运行时执行。 |
运行时多态示例
让我们看一个简单的C++运行时多态性示例。
//没有virtual关键字的示例。
#include <iostream> using namespace std; class Animal { public: void eat(){ cout<<"Eating..."; } }; class Dog: public Animal { public: void eat() { cout<<"Eating bread..."; } }; int main(void) { Dog d = Dog(); d.eat(); return 0; }
输出:
Eating bread...
运行时多态示例-通过使用两个派生类
让我们看看C++中运行时多态的另一个示例,其中有两个派生类。
//一个带有虚拟关键字的示例。
#include <iostream> using namespace std; class Shape { // 基类 public: virtual void draw(){ // 虚函数 cout<<"drawing..."<<endl; } }; class Rectangle: public Shape // 继承 Shape 类。 { public: void draw() { cout<<"drawing rectangle..."<<endl; } }; class Circle: public Shape // 继承 Shape 类。{
public:
void draw()
{
cout<<"drawing circle..."<<endl;
}
};
int main(void) {
Shape *s; // 基类指针。 Shape sh; //基类对象。 Rectangle rec;
Circle cir;
s=&sh;
s->draw();
s=&rec;
s->draw();
s=?
s->draw();
}
输出:
drawing... drawing rectangle... drawing circle...
数据成员多态示例
运行时多态可以通过C++中的数据成员来实现。让我们看一个例子,其中我们通过引用变量访问字段,引用变量引用派生类的实例。
#include <iostream> using namespace std; class Animal { //基类声明。 public: string color = "Black"; }; class Dog: public Animal //继承动物类。 { public: string color = "Grey"; }; int main(void) { Animal d= Dog(); cout<<d.color; }
输出:
Black