--------------siwuxie095
多态
多态 是面向对象的三大特征之一,其它两大特征分别
是 封装 和 继承
所谓 多态,简单来说,就是当发出一条命令时,不同的对象
接收到同样的命令后所做出的动作是不同的
而书本上的定义则是:
其实就是在说两个概念:静态多态 和 动态多态
静态多态
静态多态,也叫 早绑定
看如下实例:
定义一个矩形类:Rect,其中有两个同名成员函数:calcArea(),显然
二者互为重载(名字相同,参数可辨)
在使用时:
当实例化一个 Rect 的对象后,就可以通过对象分别调用这两个函数,
计算机在编译时,就会自动调用对应的函数
即 程序运行之前,在编译阶段就已经确定下来到底要使用哪个函数,
可见:很早就已经将函数编译进去了,称这种情况为 早绑定 或 静态
多态
动态多态
动态多态,也叫 晚绑定
看如下实例:
当前要计算面积,于是分别给圆形和矩形下达计算面积的指令,
作为圆形来说,它有自己计算面积的方法,作为矩形来说,它
也有自己计算面积的方法
显然,两种计算面积的方法肯定不同,即 对不同对象下达相同
指令,却做着不同的操作,称之为 晚绑定 或 动态多态
动态多态 是有前提的,它必须以 封装 和 继承 为基础。在封装中,
将所有数据封装到类中,在继承中,又将封装着的各个类使其形成
继承关系
只有以封装和继承为基础,才能谈到动态多态,动态多态
最起码有两个类,一个子类,一个父类,只有使用三个类
时,动态多态才表现的更为明显
看如下实例:
定义一个形状类:Shape,它有一个计算面积的成员函数:calcArea()
再定义一个圆类:Circle,它公有继承了形状类 Shape,并有自己的
构造函数和计算面积的函数
圆类计算面积的成员函数在实现时:3.14 * m_dR * m_dR
再定义一个矩形类:Rect,它公有继承了形状类 Shape,并有自己的
构造函数和计算面积的函数
矩形类计算面积的成员函数在实现时:m_dWidth * m_dHeight
在使用时:
可以使用父类指针指向子类对象,但结果却不尽如人意,因为调用到
的都是父类的计算面积的函数,即 会打印出两行 calcArea
如果想要实现动态多态,就必须使用 虚函数
虚函数
用 virtual 修饰成员函数,使其成为 虚函数
如下:在父类中,把想要实现多态的成员函数前加上 virtual 关键字,
使其成为 虚函数
在定义子类 Circle 时,给计算面积的同名函数也加上 virtual 关键字:
这里的 virtual 关键字不是必须的,如果不加,系统会自动为你加上,
而加上了,会在后续的使用中看的更加明显,推荐在子类的定义中也
加上 virtual 关键字
同理,定义子类 Rect 时,给计算面积的同名函数也加上 virtual 关键字:
最后,在使用时:
使用父类指针指向子类对象,调用函数时,调用的就是对应子类的
计算面积函数
程序:
Shape.h:
#ifndef SHAPE_H #define SHAPE_H //在每一个 .h 文件中都使用了宏定义 //宏定义是为了避免重复包含所写的 #include <iostream> using namespace std;
class Shape { public: Shape();
//这里加上了关键字virtual 会被继承到子类中 //子类的析构函数即便不写virtual 编译器会自动加上 //推荐给子类也写上这样看的清楚也是一种好的编程习惯 virtual ~Shape();
//这里加上了关键字virtual 会被继承到子类中 //子类的calcArea()即便不写virtual 编译器会自动加上 //推荐给子类也写上这样看的清楚也是一种好的编程习惯 virtual double calcArea(); };
#endif |
Shape.cpp:
#include "Shape.h"
Shape::Shape() { cout << "Shape()" << endl; }
Shape::~Shape() { cout << "~Shape()" << endl; }
double Shape::calcArea() { cout << "Shape->calcArea()" << endl; return 0; } |
Rect.h:
#ifndef RECT_H #define RECT_H #include "Shape.h" class Rect :public Shape { public: Rect(double width, double height); virtual ~Rect(); virtual double calcArea(); protected: double m_dWidth; double m_dHeight; };
#endif |
Rect.cpp:
#include "Rect.h"
Rect::Rect(double width, double height) { m_dWidth = width; m_dHeight = height; cout << "Rect()" << endl; }
Rect::~Rect() { cout << "~Rect()" << endl; }
double Rect::calcArea() { cout << "Rect->calcArea()" << endl; return m_dWidth*m_dHeight; } |
Circle.h:
#ifndef CIRCLE_H #define CIRCLE_H #include "Shape.h" class Circle :public Shape { public: Circle(double r); virtual ~Circle(); virtual double calcArea(); protected: double m_dR; };
#endif |
Circle.cpp:
#include "Circle.h"
Circle::Circle(double r) { m_dR = r; cout << "Circle()" << endl; }
Circle::~Circle() { cout << "~Circle()" << endl; }
double Circle::calcArea() { cout << "Circle->calcArea()" << endl; return 3.14*m_dR*m_dR; } |
main.cpp:
#include<stdlib.h> #include "Rect.h" #include "Circle.h"
int main(void) { Shape *shape1 = new Rect(3, 6); Shape *shape2 = new Circle(5);
//如果calcArea()不声明为虚函数则会调用父类的calArea()函数 //输出两个 Shape->calcArea() shape1->calcArea(); shape2->calcArea();
//若想通过delete父类指针来释放子类申请的内存则必须使用虚析构函数 delete shape1; shape1 = NULL; delete shape2; shape2 = NULL; system("pause"); return 0; }
//此即为动态多态(又称晚绑定)动态多态必须建立在封装和继承的基础上 //至少两个类不同对象收到相同消息(函数)此例即是 // //而静态多态(又称早绑定)如在一个类中的互为重载的函数在对象调用 //两个函数即相同对象收到不同消息(函数) |
运行一览:
【made by siwuxie095】