C++ 多态怎么用?详细解释实现和例子?

文章导读
Previous Quiz Next 单词 polymorphism 表示具有多种形式。通常,当存在 class 层次结构并且它们通过继承相关联时,就会发生 polymorphism。
📋 目录
  1. Virtual Function
  2. Pure Virtual Functions
A A

C++ 中的多态



Previous
Quiz
Next

单词 polymorphism 表示具有多种形式。通常,当存在 class 层次结构并且它们通过继承相关联时,就会发生 polymorphism。

C++ 中的 polymorphism 意味着对 member function 的调用将根据调用该 function 的 object 类型而执行不同的 function。

考虑以下示例,其中一个 base class 被其他两个 class 派生 −

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }
      int area() {
         cout << "父类面积:" << width * height << endl;
         return width * height;
      }
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Rectangle 类面积:" << width * height << endl;
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Triangle 类面积:" << (width * height)/2 << endl;
         return (width * height / 2); 
      }
};

// 程序的主函数
int main() {
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // 存储 Rectangle 的地址
   shape = &rec;
   
   // 调用 rectangle 面积。
   shape->area();

   // 存储 Triangle 的地址
   shape = &tri;
   
   // 调用 triangle 面积。
   shape->area();
   
   return 0;
}

当上述代码编译并执行时,会产生以下结果 −

Parent class area :70
Parent class area :50

输出不正确的原因是,编译器将 function area() 的调用固定设置为 base class 中定义的版本。这被称为 function 调用静态解析,或静态链接 - function 调用在程序执行前就被固定。这有时也被称为早绑定,因为 area() function 在程序编译期间就被设置。

现在,让我们对程序进行一个小修改,在 Shape class 中 area() 的声明前加上关键字 virtual,使其看起来如下 −

#include <iostream>
using namespace std;

class Shape {
   protected:
      int width, height;

   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }
      virtual int area() {
         cout << "父类面积:" << width * height << endl;
         return width * height;
      }
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }

      int area () {
         cout << "Rectangle 类面积:" << width * height << endl;
         return (width * height);
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }

      int area () {
         cout << "Triangle 类面积:" << (width * height)/2 << endl;
         return (width * height / 2);
      }
};

// 程序的主函数
int main() {
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // 存储 Rectangle 的地址
   shape = &rec;

   // 调用 rectangle 面积。
   shape->area();

   // 存储 Triangle 的地址
   shape = &tri;

   // 调用 triangle 面积。
   shape->area();

   return 0;
}

进行这个小修改后,当之前的示例代码编译并执行时,会产生以下结果 −

Rectangle class area :70
Triangle class area :25

这一次,编译器查看指针的内容而不是其类型。因此,由于 tri 和 rec class 的 object 地址存储在 *shape 中,因此调用了相应的 area() function。

如你所见,每个子类都有 function area() 的独立实现。这就是 polymorphism 的一般用法。你有不同 class,它们具有相同名称的 function,甚至相同的参数,但实现不同。

Virtual Function

virtual 函数是在基类中使用关键字 virtual 声明的函数。在基类中定义一个 virtual 函数,并在派生类中提供另一个版本,这向编译器表明我们不希望该函数使用静态链接。

我们希望的是,在程序的任何给定点调用函数时,根据被调用对象的类型来选择要调用的函数。这种操作被称为 dynamic linkage,或 late binding

Pure Virtual Functions

有时,你可能希望在基类中包含一个 virtual 函数,以便在派生类中重新定义它以适应该类的对象,但是在基类中无法为该函数提供有意义的定义。

我们可以将基类中的 virtual 函数 area() 修改为以下形式 −

class Shape {
   protected:
      int width, height;

   public:
      Shape(int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      
      // 纯虚函数
      virtual int area() = 0;
};

= 0 告诉编译器该函数没有函数体,上面的 virtual 函数将被称为 pure virtual function