【C++】多态(早期绑定、后期绑定)、抽象类(纯虚函数)、虚析构函数
我们都知道面向对象编程的三大特征是封装、继承、多态,今天我们就来说一下其中之一的多态。
概念:
多态:
多态字面意思就是多种形态,C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。(取自菜鸟教程)
多态分类:
多态分为编译时多态(早期绑定)和运行时多态(后期绑定)
编译时多态(早期绑定=静态联编)
概念:
通过函数重载和运算符重载来实现。
特点:
在编译时我们就已经知道调用的是哪些个函数
看下面的代码:
int Max(int a, int b) { return a > b ? a : b }
char Max(char a, char b) { return a > b ? a : b }
double Max(double a, double b) { return a > b ? a : b }int main()
{int x = Max(12, 23);char ch = Max('a', 'b');double de = Max(12.23, 34.45);return 0;
}
上述代码我们通过重载函数Max来实现早期绑定,也就是在我们编译的时候通过函数重载的机制就已经知道调用的是哪个函数,比如Max(12,23)参数为int整型类型的参数,所以我们就知道调用的是第一个int Max()这个函数。
运行时多态(动态绑定=动态联编)
概念:
运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。它是通过类继承关系public和虚函数来实现的。
特点:
同一个方法在不同的对象身上体现出来不同的代码形式,但是我们有统一的接口,例如下面代码中的fun函数这个方法,在基类中和派生类中体现出来的方法不一样!!!
就是说运行时多态是通过虚函数来实现的。虚函数在我上一篇说过:【C++】虚函数_神厨小福贵!的博客-CSDN博客虚函数是构成C++多态的重要一步,今天来说一下虚函数!虚函数:在基类(或父类)中,使用virtual关键字对函数进行声明为并在一个或多个派生类(子类)中被重新定义的成员函数,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。它的用法是这样的:virtual + 函数返回类型 + 函数名 +(参数表) {函数体}首先我们要知道为什么要有虚函数这个东西?我来看下下面这两段代码的结果再来说结果:class A{public:void fun(){couthttps://blog.csdn.net/qq_45829112/article/details/123460960?spm=1001.2014.3001.5502
下面我那代码来实现一下动态绑定:
class A
{
public:virtual void fun(){}
};class B :public A
{
public:virtual void fun(){cout << "class B::fun()" << endl;}
};class C :public A
{
public:virtual void fun(){cout << "class C::fun()" << endl;}
};void pun(A& a)
{a.fun();
}int main()
{B b;C c;pun(b);pun(c);return 0;
}
类B、C都公有继承类A,然后创建bc对象,分别调用函数pun,当传入参数为class B参数时 调用B中的妇女函数,传参为class C时,调用类C中的fun函数!、
上述代码解析如下图所示:
运行结果:
这就是简单的运行时的多态,相同的方法在不同的 不同对象下进行调用时,产生的结果也不尽相同,这也就是简单的运行时的多态!!!
抽象类(纯虚函数)
概念:
含有纯虚函数的类称为抽象类。纯虚函数没有实现部分,不能产生对象。
简单来说就是抽象类(有纯虚函数的类)不能定义对象!!!
virtual 类型 函数名(参数列表)= 0 如下所示:
virtual void fun() { } = 0;
下面来说下纯虚函数的特点:
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。
可能会有些抽象,举个简单例子就是说,你说你要去混社会去了,但是有社会这个实体这个对象嘛,显然是没有的,我们只能在社会上做某些事情,而没有社会这个实体,大致就这么个意思!!!
那么纯虚函数以及这个抽象类有什么作用呢???
class A
{
public:virtual void fun() {} = 0; //纯虚函数
};class B :public A
{
public:virtual void fun() //必须要进行重写,否则class B也是一个抽象类,不可以定义对象{cout << "class B::fun()" << endl;}
};class C :public A
{
public:virtual void fun() //必须要进行重写,否则class C也是一个抽象类,不可以定义对象{cout << "class C::fun()" << endl;}
};
抽象类一般作为接口来使用,真正的实现都是在其派生类中进行实现,如上述代码中所示,在基类A中的fun啥也不干,仅仅搞个纯虚函数,真正的实现都是在其派生类class B和class C中来进行实现的。
析构函数为什么声明为虚函数???
class A
{
public:A(int x = 10){cout << "A构造函数运行" << endl;}virtual void fun(){}~A(){cout << "~A运行" << endl;}
};class B :public A
{
public:B(int x = 10){cout << "B构造函数运行" << endl;}~B(){cout << "~B运行" << endl;}virtual void fun(){cout << "class B::fun()" << endl;}
};int main()
{A* op = new B(10);op->fun();delete op;op = nullptr;return 0;
}
观察上述代码,父类指针指向派生类对象,完成执行fun函数之后,我们对op指针所指向资源进行释放以及置空,运行结果:
为啥上面我们构造了两次,最后释放却只释放了一次呢?
原因是我们op是基类指针,指向派生类的对象,构造class B的无名对象的时候,先构造A的隐藏父对象,再构造B对象,但是我们释放的时候因为是基类指针,所以只能找到基类的析构函数,所以我们派生类的对象就没有进行释放,可能会造成内存泄漏!!!
怎么解决这个问题呢?父类析构函数加虚声明virtual:
class A
{
public:A(int x = 10){cout << "A构造函数运行" << endl;}virtual void fun(){}virtual ~A() //构造函数加virtual声明{cout << "~A运行" << endl;}
};class B :public A
{
public:B(int x = 10){cout << "B构造函数运行" << endl;}~B(){cout << "~B运行" << endl;}virtual void fun(){cout << "class B::fun()" << endl;}
};int main()
{A* op = new B(10);op->fun();delete op;op = nullptr;return 0;
}
至于派生类的析构函数,我们可以加也可以不加,因为如果我们派生类还有派生类的话,就得加virtual声明,下面我们来看运行结果:
我们在基类中将析构函数声明为virtual虚函数,派生类相当于继承了虚函数这个特性,所以析构的时候,就可以通过虚表指针来找到派生类中的虚函数来对派生类对象进行析构!!!
【C++】多态(早期绑定、后期绑定)、抽象类(纯虚函数)、虚析构函数相关推荐
- 构造函数不可以是虚函数;析构函数可以是虚函数,也可以是纯虚函数。
构造函数不可以是虚函数:析构函数可以是虚函数,也可以是纯虚函数. 一:构造函数不能声明为虚函数的原因 1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的. 而在构造 ...
- 38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】
虚函数.虚基类.纯虚函数 (一).虚函数 1.什么是虚函数: 2.虚函数的格式: 3.关于虚函数的注意事项: 4.虚函数的作用: 5.虚函数访问格式 6.虚函数的各种疑难杂症 [当指针是基类.但虚函数 ...
- c语言中虚函数和纯虚函数,虚函数和纯虚函数的区别是什么?
虚函数和纯虚函数的区别:1.纯虚函数只有定义,没有实现:而虚函数既有定义,也有实现的代码.2.包含纯虚函数的类不能定义其对象,而包含虚函数的则可以. 相关推荐:<C++视频教程> 虚函数( ...
- 虚函数 虚继承 抽象类
虚函数.纯虚函数.虚基类.抽象类.虚函数继承.虚继承 虚函数:虚函数是C++中用于实现多态(polymorphism)的机制.核心理念就是通过基类访问派生类定义的函数.是C++中多态性的一个重要体现, ...
- 虚函数 纯虚函数 虚基类说明
原文:http://www.cnblogs.com/ms-frank/archive/2008/01/16/1041310.html 虚基类 在说明其作用前先看一段代码 [cpp] view plai ...
- 虚函数、纯虚函数、虚函数与析构函数
一.虚函数 只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个 ...
- 【C++】多态 - 虚函数/虚析构函数以及虚函数表
什么是多态: 指不同对象收到相同消息时或相同对象收到不同消息时产生不同的动作. 这里先说下为什么会用到虚函数: 以下面的程序为例: 这个程序中,Carp是Fish的继承类,而Carp中覆盖了Swim这 ...
- c++ 中 virtual / 纯虚函数(析构函数)测试
为什么80%的码农都做不了架构师?>>> #include <iostream> #include <string>using namespace st ...
- C++学习12:C++多态、虚函数、虚析构函数、纯虚函数、抽象类
一 多态概述 C++中的多态分为静态多态和动态多态.静态多态是函数重载,在编译阶段就能确定调用哪个函数.动态多态是由继承产生的,指同一个属性或行为在基类及其各派生类中具有不同的语义,不同的对象根据所接 ...
- VB6的后期绑定和前期绑定
1. 什么是后期绑定和前期绑定后期绑定 MSDN 6的定义如下: 后期绑定:若将一个变量声明为 As Object 或 As Variant(包括 As Form 或 As Control 的变量), ...
最新文章
- Android多进程引发的问题
- gerber文件怎么导贴片坐标_利用Gerber文件生成贴片坐标及元件位置图的方法技巧...
- 系统架构设计师 - 23种设计模式(GOF)
- python 字符串替换_python字符串替换的2种方法
- EF-使用EF写SQL语句
- 学习JSON的神级网站www.bejson.com
- 笔记本光驱在计算机里不显示器,笔记本如何打开光驱_笔记本光盘怎么打开来...
- 【转】你所知道与不知道的游戏机发展史 60-90年代
- 目前比较好用的同步网盘@2012
- 启动到APP的设置页,小米手机自启动管理页,小米手机APP权限管理页
- c语言中正弦函数的定义,三角函数基本概念 | 玄数
- Android 广播(Broadcast)
- 苹果研发microLED暂难摆脱对三星的依赖
- 【Nodejs】留言板案例
- Ext 4 概述(一)
- 数学问 高考数学复习资料策略整理
- 中国农业科学院培训中心职业技能等级证书及培训证书
- java表示一个数的二进制数,怎么表示一个二进制数?
- 杨春歌 简单谈谈OC与Swift的异同
- Java项目一(案例):家庭收支记账软件
热门文章
- MindSpore部署图像分割示例程序
- 2021年大数据ELK(二十八):制作Dashboard
- CSS盒模型( CSS margin 属性)
- Error:Unsupported method: BaseConfig.getApplicationIdSuffix(). The version o
- sqli-labs:5-6,盲注
- n皇后问题JS实现(N-Queens)
- 判断路径下文件是否存在
- 2022-2028年中国生物类似药产业深度调研及前瞻分析报告
- Linux Supervisor的安装与使用入门
- 【JBOSS】User not found SA