多态形成的三要素

上一篇文章中,我们看到了简单的赋值兼容模型,将子类赋值给父类对象时,调用共有的同名接口时,调用的依然还是父类的成员函数。在 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都是子类的方法。

2015-05-24_230308

以上这种情况,被称为多态,当然你可能现在感觉不到它存在的意义,在以后的小案例中,你会不断的看到这种情况的出现。没有多态,C++可能没有那么出色。正是类和多态,给 C++ 带来了无数神秘的色彩。最后我们总结一下,多态形成的三个条件:

  1. 是父类中有虚函数。
  2. 子类 override(覆写)父类中的虚函数。
  3. 通过己被子类对象赋值的父类指针,调用共用接口。

说说你的想法