虚函数

--------------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】

原文地址:https://www.cnblogs.com/siwuxie095/p/6805965.html