C++ 虚函数、虚析构、虚构造(原创纯手码)
虚函数
- 1. 前言
- 2. 具体使用
- 3. 虚析构
- 4. 虚构造
- 5. 纯虚函数
1. 前言
虚函数的概念是在类继承中提出的,为了让派生类重新实现基类的方法。当对象指针/引用指向的类型来调用具体的方法。
在基类声明中使用关键字virtual标记可以被重写的方法,派生类中可以使用该关键字,也可以不用(效果一样)。
注意:virtual关键字只需在声明中添加,在源代码中无需添加。这点和static、inline关键字一致。
virtual void printOrg();//基类声明中的虚函数
2. 具体使用
- 如果没有使用关键字virtual,程序将根据引用/指针类型选择方法。
举例说明:
#include <iostream>using namespace std;
//基类源码
class COriginal
{public:COriginal();~COriginal();void printOrg();
};//基类源码
COriginal::COriginal()
{cout << "Constructor of COriginal" << endl;
}void COriginal::printOrg()
{cout << "printOrg of COriginal" << endl;
}COriginal::~COriginal()
{cout << "Destruct of COriginal" << endl;
}//派生类声明
class CDerive :public COriginal
{public:CDerive();~CDerive();void printOrg();
};//派生类源码
CDerive::CDerive()
{ cout << "Constructor of CDerive" << endl;}void CDerive::printOrg()
{cout << "printOrg of CDerive" << endl;
}CDerive::~CDerive()
{ cout << "Destruct of CDerive" << endl;}int main()
{COriginal *pOrg = new CDerive;pOrg->printOrg();delete pOrg;return 0;
}
输出:
Constructor of COriginal
Constructor of CDerive
printOrg of COriginal
Destruct of COriginal
逐行分析打印,① new派生类对象时,需要先调用基类构造函数;② 调用派生类构造函数;③ 基类方法printOrg没有使用virtual关键字修饰,即没有声明为虚函数。所以根据pOrg指针的类型调用COriginal的方法;④ 释放pOrg内存后,自动调用析构(和第三点一样,所以调用的基类析构函数)。
Q:为什么创建派生对象时需要先调用基类构造?
A:基类构造函数负责初始化继承的数据成员,派生类构造函数主要用于初始化新增的数据成员。
- 如果使用virtual,程序将根据引用/指针指向的对象的类型选择方法。
举例说明
#include <iostream>using namespace std;
//基类源码
class COriginal
{public:COriginal();~COriginal();virtual void printOrg();
};//基类源码
COriginal::COriginal()
{cout << "Constructor of COriginal" << endl;
}void COriginal::printOrg()
{cout << "printOrg of COriginal" << endl;
}COriginal::~COriginal()
{cout << "Destruct of COriginal" << endl;
}//派生类声明
class CDerive :public COriginal
{public:CDerive();~CDerive();virtual void printOrg();//单纯作为派生类,该virtual关键字仅为了标识,可以不加
};//派生类源码
CDerive::CDerive()
{ cout << "Constructor of CDerive" << endl;
}void CDerive::printOrg()
{cout << "printOrg of CDerive" << endl;
}CDerive::~CDerive()
{cout << "Destruct of CDerive" << endl;
}int main()
{COriginal *pOrg = new CDerive;//指针类型为COriginal,对象类型是CDerivepOrg->printOrg();delete pOrg;return 0;
}
输出:
Constructor of COriginal
Constructor of CDerive
printOrg of CDerive
Destruct of COriginal
逐行分析打印,① new派生类对象时,需要先调用基类构造函数;② 调用派生类构造函数;③ 基类方法printOrg使用virtual关键字修饰,即声明为虚函数。所以需要根据pOrg指针指向对象的类型(new CDerive返回的类型为CDerive) 调用CDerive的方法;④ 释放pOrg内存后,自动调用析构(因为基类析构没有用虚方法,指针类型是COriginal,所以调用基类析构)。
3. 虚析构
析构函数在对象生命周期结束时被自动调用,动态联编的方式和其他方法没区别。从上面的例子可以看出,析构函数符合“如果没有使用关键字virtual,程序将根据引用/指针类型选择方法。如果使用virtual,程序将根据引用/指针指向的对象的类型选择方法。”
正确的做法,需要在基类中将析构函数声明为虚方法。这样做是为了确保释放派生对象时,按正确的顺序调用析构函数。
举例说明:
#include <iostream>using namespace std;
//基类源码
class COriginal
{public:COriginal();virtual ~COriginal();virtual void printOrg();
private:int *m_pOrg;
};//基类源码
COriginal::COriginal()
{m_pOrg = new int;//就是想在堆中申请内存cout << "Constructor of COriginal" << endl;
}void COriginal::printOrg()
{cout << "printOrg of COriginal" << endl;
}COriginal::~COriginal()
{delete m_pOrg;//内存释放cout << "Destruct of COriginal" << endl;
}//派生类声明
class CDerive :public COriginal
{public:CDerive();~CDerive();virtual void printOrg();//单纯作为派生类,该virtual关键字仅为了标识,可以不加
private:int *m_pDrv;
};//派生类源码
CDerive::CDerive()
{ m_pDrv = new int;//就是想在堆中申请内存cout << "Constructor of CDerive" << endl;
}void CDerive::printOrg()
{cout << "printOrg of CDerive" << endl;
}CDerive::~CDerive()
{ delete m_pDrv;//内存释放cout << "Destruct of CDerive" << endl;
}int main()
{COriginal *pOrg = new CDerive;//指针类型为COriginal,对象类型是CDerivepOrg->printOrg();delete pOrg;return 0;
}
输出:
Constructor of COriginal
Constructor of CDerive
printOrg of CDerive
Destruct of CDerive
Destruct of COriginal
在将基类析构声明为虚方法以后,终于会根据指针指向的对象类型调用析构方法了。还是逐行分析打印,① new派生类对象时,需要先调用基类构造函数;② 调用派生类构造函数;③调用CDerive的printOrg 方法;④ 释放pOrg内存后,因为基类析构被声明为virtual,将根据pOrg指向的对象类型调用派生类析构。⑤ 该对象过期,程序调用基类析构,C++规定的,没有做特殊说明……
4. 虚构造
首先明确,虚构造是有问题的。
根据准则“如果没有使用关键字virtual,程序将根据引用/指针类型选择方法。如果使用virtual,程序将根据引用/指针指向的对象的类型选择方法。”,若基类构造被声明为虚函数,一旦指针/引用指向的对象类型是派生类,将不会调用基类构造。
举例说明:
error: constructors cannot be declared 'virtual' [-fpermissive]
直接报错了……,编译器都看不下去了。
5. 纯虚函数
作为接口类的,基类中声明中定义的方法,没有具体实现,所以要求派生类实现该方法。纯虚函数的特征是末尾有“=0”的标志,如下:
virtual void printOrg()=0;
没啥好说的,贴一下菜鸟教程纯虚函数的解释吧。
C++ 虚函数、虚析构、虚构造(原创纯手码)相关推荐
- C++继承、虚函数、覆盖、多态、纯虚函数
一.什么是继承 1.当遇到问题时,先查看现有的类能够解决一部分问题,如果有则继承该类,在此类的基础上进行扩展来解决问题,以此可以缩短解决问题的时间(代码复用) 2.当遇到一个大而复杂的问题时,可以先把 ...
- 析构函数可以为纯虚函数吗?纯虚函数可以有函数体吗?纯虚函数需要函数体吗?
先回答标题中中的几个问题: 析构函数可以为纯虚函数吗? yes. 纯虚函数可以有函数体吗? yes. 纯虚函数需要函数体吗? 一般来讲,如果析构函数是纯虚函数,那么析构函数必须要有函数体,如果是其它函 ...
- 虚函数 2 之虚函数的定义
1.虚函数的定义 虚函数就是在基类中被关键字 virtual 说明,并在派生类中重新定义的函数. 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的 ...
- 虚函数原理与虚函数表
目录 一. 虚函数 二.虚函数原理与虚函数表 一. 虚函数 虚函数: 使用 virtual 关键字声明的函数,是动态多态实现的基础. 非类的成员函数不能定义为虚函数. 类的静态成员函数不能定义为虚函数 ...
- 虚函数的实质——虚函数表
目录 虚函数的实质--虚函数表 虚函数表是什么? 虚函数表长什么样? 证明了确实存在隐藏的虚函数表指针 派生类指针转换为基类类型的实质 当基类指针指向派生类对象时,虚函数表会如何变化? 虚函数的实质- ...
- C++多态的原理(虚函数指针和虚函数表)
C++多态的原理 (虚函数指针和虚函数表) 1.虚函数指针和虚函数表 2.继承中的虚函数表 2.1单继承中的虚函数表 2.2多继承中的虚函数表 3.多态的原理 4.总结 1.虚函数指针和虚函数表 以下 ...
- 【C++】虚函数指针和虚函数列表
本篇文章主要来讲述,C++多态的实现原理,也就是虚函数和虚函数列表是怎么回事?它们是如何实现多态的? 虚函数概述: 首先,C++多态的实现是通过关键字virtual,有了这个关键字之后,通过继承的关系 ...
- C++虚函数继承与虚继承
虚函数继承和虚继承是完全不同的两个概念. 虚函数继承是解决多态性的,当用基类指针指向派生类对象的时候,基类指针调用虚函数的时候会自动调用派生类的虚函数,这就是多态性,也叫动态编联. 虚继承就是为了节约 ...
- 什么是纯虚函数 纯虚函数的作用 如何定义使用纯虚函数
什么是纯虚函数 纯虚函数的作用 如何定义使用纯虚函数 一 定义: 纯虚函数是一种特殊的虚函数,它的一般格式如下: class <类名> { virtual <类型>& ...
最新文章
- 【jsp】jsp的内置对象(部分)
- Linux函数名加数字,C++ 编译器的函数名修饰规则
- 数据库以及后台开发之写在前面
- 011_html标题
- ubuntu 安装git
- 【JVM性能调优】使用jstack找出最耗CPU的java线程
- 利用Basic authentication 测试不同user的metadata access request
- Python库大全涵盖了Python应用的方方面面建议收藏留用!
- Python 机器学习 随机森林 天气最高温度预测任务(三)
- 文章之间的基本总结Activity生命周期
- 数组保存为灰度图_「PS抠图系列9」通道
- 11.PHP-FPM pool
- 查询优化器内核剖析第六篇:谈谈Join的顺序问题,纠正江湖偏方
- tensorflow2 unet加载自己的图像进行训练
- 计算机信息系统发生安全事故,网络安全事故报告制度
- java实现在线预览----poi操作word转html及03、07版本兼容问题
- IEEE1588精密网络同步时钟协议(PTP)-v2.0协议浅析
- ubuntu虚拟机上外网设置
- cocos2dx 3.2 学习篇之六(精灵运动,自定义运动轨迹(太极八卦))
- Python学习Day01
热门文章
- IIS中FTP登陆用户名密码都对但进不去的另一种原因
- NBIOT模块 ME3616 AT命令 MQTT 连接 thingsboard
- DL4J中文文档/开始/Eclipse DL4J示例之旅
- Graphx中pregel详解及具体应用分析(以最短路径为例)
- ruby 实现 bing 的 geocode
- MAC M1安装telnet
- 【转】VMWare+WinDbg搭建(驱动)调试环境
- 尘缘如梦_转载网友_天还是那么蓝
- python tkinter获取屏幕大小_Tkinter根窗口设置小技巧:程序启动最大化和程序窗口图标设置...
- Android使用Glide加载Gif慢 获取gif时间