前言
通过前两篇博文,我已经将多态的前提条件总结得七七八八了。这一篇开始正式展开讲多态,以及我们为什么要使用多态。
多态
什么是多态
引用百度百科的定义:
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
我的理解是:子类可以通过父类的指针或者引用,调用子类重写父类的虚函数,以达到一个类型多种状态的效果。
这听起来好像没有什么,我可以直接通过子类的对象调用成员函数不就行了,为啥还要舍近求远将其赋值到一个父类指针再调用呢?起初学习的时候我也不懂为什么,直到后来我遇到了一个很典型的例子才恍然大悟,这个例子我会在下面讲到。
多态的条件
前面也零零散散地介绍了C++多态的条件,这里总结一下:
- 需要有继承
- 需要使用父类的指针或引用
- 父类需要有虚函数,子类要重写父类的虚函数
需要上转型是Java多态的条件,C++主要是通过使用父类的指针或者引用来实现的,也可以认为是一种上转型吧。正是因为使用了父类的指针或者引用,才使得他能够调用子类的虚函数,而不是像上一篇的上转型导致的静态绑定,最终调用的是父类的虚函数。我们通过以下代码来回顾一下:
class base
{
public:
virtual void do_something() //有虚函数
{
cout << "I'm base class" << endl;
}
};
class derived : public base //有继承
{
public:
void do_something() //子类重写了父类的虚函数
{
cout << "I'm derived class" << endl;
}
};
void fun1(base &b) //父类的引用
{
b.do_something();
}
void fun2(base *b) //父类的指针
{
b->do_something();
}
void fun3(base b)
{
b.do_something();
}
int main() {
derived d;
fun1(d); //I'm derived class
fun2(&d); //I'm derived class