C++中的虚函数

    科技2022-08-13  98

    文章目录

    多态虚函数

    多态

    多态是面向对象的三大特征之一,其它两大特征分别是 封装 和 继承

    所谓 多态,简单来说,就是当发出一条命令时,不同的对象

    接收到同样的命令后所做出的动作是不同的

    而书本上的定义则是:

    其实就是在说两个概念:静态多态和动态多态

    静态多态

    静态多态,也叫 早绑定

    看如下实例:

    定义一个矩形类: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 编译器会自动加上 //推荐给子类也写上这样看的清楚也是一种好的编程习惯 virtualdouble calcArea(); }; #endif

    Shape.cpp:

    #include"Shape.h" Shape::Shape() { cout << "Shape()" << endl; } Shape::~Shape() { cout << "~Shape()" << endl; } double Shape::calcArea() { cout << "Shape->calcArea()" << endl; return0; }

    Rect.h:

    #ifndef RECT_H #define RECT_H #include"Shape.h" class Rect :public Shape { public: Rect(double width, double height); virtual ~Rect(); virtualdouble 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(); virtualdouble 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; return3.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"); return0; }

    //此即为动态多态(又称晚绑定)动态多态必须建立在封装和继承的基础上

    //至少两个类不同对象收到相同消息(函数)此例即是

    //

    //而静态多态(又称早绑定)如在一个类中的互为重载的函数在对象调用

    //两个函数即相同对象收到不同消息(函数)

    运行一览:

    转载链接:https://blog.csdn.net/siwuxie095/article/details/71159414

    Processed: 0.014, SQL: 9