当发出一条命令时,不同对象接收到相同的命令后,所作出的动作不同。
严谨说:相同对象收到不同消息 or 不同对象收到相同消息时产生不同的动作。
class Rect{ public: int calcArea(int width); int calcArea(int width,int height); };
定义的一个矩形类Rect中,定义2个成员函数(名字相同),但是2个函数的参数不同,他们是互为重载的函数。
静态绑定:根据传参的个数,计算机在编译时自动地调用相应的函数,即在运行前的编译阶段,函数的程序(调用哪个)已经确定下来了。
圆形类和矩形类(不同对象)分别由自己的计算机面积的方法,但方法不同,即下达相同命令给不同对象,却做着不同的操作。
动态多态的前提:以封装和继承为基础。
在一个形状类Shape类中,定义了一个成员函数(计算面积):
class Shape{ public: double calcArea(){ cout<<"calcArea()"<<endl; return 0; } }
再定义2个类,这两个类都是以public方式继承shape类。
先是圆形类:
class Circle:public Shape{ public: Circle(double r){//构造函数 m_dR=r; } double calcArea(); private: double m_dR; }; double Circle::calcArea(){ return 3.14*m_dR*m_dR; }
再是矩形类:
class Rect:public Shape{ public: Rect(double width,double height){//构造函数 m_dWidth=width; m_dHeigth=height; } double calcArea(); private: double m_dWidth; double m_dHeigth; }; double Rect::calcArea(){ return m_dWidth*m_dHeight; }
在main函数中使用时,
可以使用父类的指针shape1指向其中的一个子类对象Circle,
并且用另一个父类指针shape2指向一个矩形的对象。
这两个子类对象都被它的父类指针所指向。
int main(){ Shape *shape1=new Circle(4.0); Shape *shape2=new Rect(3.0,5.0); shape1->calcArea(); shape2->calcArea(); return 0; }
输出的结果是2个calcArea().
采用virtual
修饰类的成员函数。
在父类shape中定义成员函数时,就把我们想要实现多态的成员函数前加virtual关键字(使其成为成员虚函数):
虚函数——“虚假”的函数,父类引用子类对象,子类成员函数重写父类方法(函数)。
写法:即将基类的calcArea
函数前加virtual,和子类Circle和子类Rect的calcArea
函数声明前面加上virtual。
#include<stdlib.h> #include<iostream> #include<stdio.h> using namespace std; class Shape{ public: virtual double calcArea(){//虚函数 cout<<"calcArea()"<<endl; return 0; } }; class Circle:public Shape{ public: //Circle(double r); virtual double calcArea(); Circle(double r){//构造函数 m_dR=r; } private: double m_dR; }; double Circle::calcArea(){//成员函数 return 3.14*m_dR*m_dR; } class Rect:public Shape{ public: Rect(double width,double height){//构造函数 m_dWidth=width; m_dHeigth=height; } virtual double calcArea(); private: double m_dWidth; double m_dHeigth; }; double Rect::calcArea(){//成员函数的实现 return m_dWidth*m_dHeigth; } int main(){ Shape *shape1=new Circle(4.0); Shape *shape2=new Rect(3.0,5.0); cout<<shape1->calcArea(); cout<<shape2->calcArea(); system("pause"); return 0; }
输出结果不再是2个calcArea(),而是调用了2个子类中重写基类的calcArea()
函数,分别计算出圆和矩形的面积。
虚函数——“虚假”的函数,父类引用子类对象,子类成员函数重写父类方法。
在主调程序中定义2个Shape类的指针(一个指向子类Rect,一个指向子类Circle)。
用两个指针分别调用计算面积的函数——看调用的父类的还是子类的面积函数;
最后将2个指针对象销毁——看销毁父类指针时,能否销毁子类的对象。
#include "Circle.h" #include<iostream> using namespace std; Circle::Circle(double r){ cout<<"Circle()"<<endl; m_dR=r; } Circle::~Circle(){ cout<<"~Circle()"<<endl; } double Circle::calcArea(){ cout<<"Circle----calcArea"<<endl; return 3.14*m_dR*m_dR; }
#include<iostream> #include<stdlib.h> #include"Circle.h" #include"Rect.h" using namespace std; int main(){ Shape *shape1=new Rect(3,6);//传入宽和高 Shape *shape2=new Circle(5);//传入半径 shape1->calcArea(); shape2->calcArea(); delete shape1; shape1=NULL; delete shape2; shape2=NULL; system("pause"); return 0; }
#include "Rect.h" #include<iostream> using namespace std; Rect::Rect(double width,double height){ cout<<"Rect()"<<endl; m_dWidth=width; m_dHeight=height; } Rect::~Rect(){ cout<<"~Rect()"<<endl; } double Rect::calcArea(){ cout<<"Rect----calcArea"<<endl; return m_dWidth*m_dHeight; }
主函数
#include"Shape.h" #include<iostream> using namespace std; Shape::Shape(){ cout<<"Shape()"<<endl; } Shape::~Shape(){ cout<<"~Shape()"<<endl; } double Shape::calcArea(){ cout<<"Shape---calcArea()"<<endl; return 0; }
(1)前四行结果:
实例化一个Rect对象
——会先执行父类的构造函数,再执行本身的构造函数。Circle实例化同理。
(2)中间两行
没有做到我们所想的调用Rect和Circle中的calcArea()函数
——解决方案:在3个头文件中的calcArea()
函数前加上virtual
,
注意子类的calcArea函数前的virtual
不是一定要加上的,不加上系统也会自动加上,但是最好加上。
都加了virtual
后的结果:
(3)最后两行
销毁Shape1和Shape2时,只执行父类的析构函数,并没有执行2个子类的析构函数。