但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示

多态的作用

这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。

在面向对象编程范式中,多态性往往表现为”一个接口,多个功能

  1. class Shape {
  2. protected:
  3. int width, height;
  4. public:
  5. Shape( int a=0, int b=0)
  6. {
  7. width = a;
  8. height = b;
  9. }
  10. // pure virtual function
  11. virtual int area() = 0;
  12. };

动态联编支持多态性

定义

编译程序在编译阶段并不能确切地指导将要调用的函数,只有在程序执行时才能确定将要调用的函数,为此要确切地指导将要调用的函数,要求联编工作在程序运行时进行,这种在 程序运行时进行的 联编工作被称为动态联编。 C++中,动态联编是在虚函数的支持下实现的 。

例子

  1. #include<iostream>
  2. using std::cout;
  3. using std::endl;
  4. class Parent
  5. {
  6. public:
  7. virtual void show() //虚函数show
  8. {
  9. cout << "parent" << endl;
  10. }
  11. void put()
  12. {
  13. cout << "基类" << endl;
  14. }
  15. };
  16. class Son : public Parent
  17. {
  18. public:
  19. void show()
  20. {
  21. cout << "son" << endl;
  22. }
  23. void put()
  24. {
  25. cout << "派生类" << endl;
  26. }
  27. };
  28. void fun(Parent& p)
  29. {
  30. p.show();
  31. }
  32. void fun(Parent& p,int) //使用占位参数重载fun。
  33. {
  34. p.put();
  35. }
  36. int main()
  37. {
  38. Parent* p = nullptr;
  39. p = new Son;
  40. Parent p1;
  41. fun(p1); //父类
  42. fun(*p); //子类
  43. cout << endl;
  44. fun(p1, 1); //父类
  45. fun(*p, 1); //子类
  46. delete p;
  47. p = nullptr;
  48. return 0;
  49. }

很明显,静态联编在编译的时候就和被调函数绑定了,只会去调用基类的put成员函数,根本不会调用派生类重写的put成员

子类对象代替父类对象作为函数入口参数

当入口参数为父类对象时,子类即便作为入口参数,最后使用的仍然是父类的方法,而入口参数是父类指针或者父类引用时,子类代替父类作为入口参数,就可以使用自己的方法。

例子

  1. #include <iostream>
  2. using namespace std;
  3. class A
  4. {
  5. public:
  6. virtual void Show() const
  7. {
  8. cout << "A ";
  9. }
  10. };
  11. class B: public A
  12. {
  13. public:
  14. void Show() const
  15. { cout << "B "; }
  16. };
  17. void Show(const A &obj) {
  18. obj.Show();
  19. }
  20. int main()
  21. {
  22. A a; B b;
  23. Show(a); Show(b);
  24. A *p;
  25. p = &a; p->Show();
  26. p = &b; p->Show();
  27. B *q;
  28. q = &b; q->Show();
  29. cout << endl;
  30. return 0;
  31. }

这里 line 18 传递参数为父类的引用,因此可以调用子类的函数。