但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示
多态的作用
这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。
在面向对象编程范式中,多态性往往表现为”一个接口,多个功能
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
动态联编支持多态性
定义
编译程序在编译阶段并不能确切地指导将要调用的函数,只有在程序执行时才能确定将要调用的函数,为此要确切地指导将要调用的函数,要求联编工作在程序运行时进行,这种在 程序运行时进行的 联编工作被称为动态联编。 C++中,动态联编是在虚函数的支持下实现的 。
例子
#include<iostream>
using std::cout;
using std::endl;
class Parent
{
public:
virtual void show() //虚函数show
{
cout << "parent" << endl;
}
void put()
{
cout << "基类" << endl;
}
};
class Son : public Parent
{
public:
void show()
{
cout << "son" << endl;
}
void put()
{
cout << "派生类" << endl;
}
};
void fun(Parent& p)
{
p.show();
}
void fun(Parent& p,int) //使用占位参数重载fun。
{
p.put();
}
int main()
{
Parent* p = nullptr;
p = new Son;
Parent p1;
fun(p1); //父类
fun(*p); //子类
cout << endl;
fun(p1, 1); //父类
fun(*p, 1); //子类
delete p;
p = nullptr;
return 0;
}
很明显,静态联编在编译的时候就和被调函数绑定了,只会去调用基类的put成员函数,根本不会调用派生类重写的put成员
子类对象代替父类对象作为函数入口参数
当入口参数为父类对象时,子类即便作为入口参数,最后使用的仍然是父类的方法,而入口参数是父类指针或者父类引用时,子类代替父类作为入口参数,就可以使用自己的方法。
例子
#include <iostream>
using namespace std;
class A
{
public:
virtual void Show() const
{
cout << "A ";
}
};
class B: public A
{
public:
void Show() const
{ cout << "B "; }
};
void Show(const A &obj) {
obj.Show();
}
int main()
{
A a; B b;
Show(a); Show(b);
A *p;
p = &a; p->Show();
p = &b; p->Show();
B *q;
q = &b; q->Show();
cout << endl;
return 0;
}
这里 line 18 传递参数为父类的引用,因此可以调用子类的函数。