上一篇文章中,我们看到了简单的赋值兼容模型,将子类赋值给父类对象时,调用共有的同名接口时,调用的依然还是父类的成员函数。在 C++ 中,有一个总要的概念,那就是多态。通过父类提供一些虚函数,让子类继承下去并实现为另外的功能,然后将子类对象的地址赋值给父类的对象指针。这样再次使用父类的指针调用共有同名接口时,你会发现它竟然调用的是子类的方法。这一切都来源于一个关键字“virtual”。
#include <iostream> using namespace std; class Shape { public: Shape(int x, int y) :_x(x), _y(y){} // 父类提供虚函数接口 virtual void draw() { cout << "draw Shap "; cout << "start (" << _x << "," << _y << ")" << endl; } protected: int _x; int _y; }; // 继承 Shape 类 class Circle : public Shape { public: Circle(int x, int y, int r) :Shape(x, y), _r(r){} // 覆写父类 virtual 接口函数 void draw() { cout << "draw Circle "; cout << "start (" << _x << "," << _y << ") "; cout << "radio r = " << _r << endl; } private: int _r; }; int main(int argc, char* argv[]) { // 实例化一个父类对象 Shape s(3, 5); s.draw(); // 实例化一个子类对象 Circle c(1, 2, 4); c.draw(); cout << "------------------------" << endl; // 子类对象给父类变量赋值,普通赋值兼容,会出现数据截断 s = c; s.draw(); // 子类对象给父类引用赋值,可构成多态 // 引用的内部实现就是包装了一个指针 Shape &rs = c; rs.draw(); // 子类对象给父类指针赋值,可构成多态 Shape *ps = &c; ps->draw(); return 0; }
以上代码运行的结果你会发现,最后两个调用的draw都是子类的方法。
以上这种情况,被称为多态,当然你可能现在感觉不到它存在的意义,在以后的小案例中,你会不断的看到这种情况的出现。没有多态,C++可能没有那么出色。正是类和多态,给 C++ 带来了无数神秘的色彩。最后我们总结一下,多态形成的三个条件:
- 是父类中有虚函数。
- 子类 override(覆写)父类中的虚函数。
- 通过己被子类对象赋值的父类指针,调用共用接口。