【C++】浅析析构函数(基类中)为什么要写成虚基类?
为什么有了虚析构函数,就能先调用子类的析构函数?
class A {virtual ~A(){}
};class B : A {virtual ~B(){}
};A *p = new B();
delete p;
唯一差别是,每个析构函数结束时会自动(隐含地)调上父类的析构函数,而普通虚函数并不会
本质上 当类里面有定义虚函数时,编译器会给类增加一个虚函数表,里面来存放虚函数指针,这样就增加了类的存储空间
会发现,当基类的析构函数不为虚函数时,当基类对象操控派生类对象以及对象成员时,当程序结束时会发现,派生类的析构没有调用,存在潜在的内存泄漏问题。(一句话,保证delete即指针时,正确运行析构函数)
1.首先说一下,析构顺序
派生类–> 成员类 --> 基类
2.为什么需要把基类设置为虚析构
因为多态
在c++中,可以使用父类指针指向子类,产生多态行为
代码
#include <iostream>
class TestFather{
public:~TestFather() {std::cout << "~TestFather()" << std::endl;}
};
class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}//
执行结果
~TestFather()
原因就是,你直接给编译器一个TestFather指针,delete的时候,编译器一看这不就是TestFather,直接调用TestFather析构函数
换成虚析构呢
代码
#include <iostream>
class TestFather{
public:virtual ~TestFather() {std::cout << "~TestFather()" << std::endl;}
};
class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}///
执行结果
~TestChild()
~TestFather()
正确了,在delete的时候,编译器会先看TestFather的析构函数是不是虚函数,如果是的话才会产生正常的析构顺序行为,派生类–>成员类–>基类
3. 虚析构函数的本质
虚析构其实也就是虚函数加上析构函数,本质就是会维护一个虚表和指向虚表的指针,在上面代码中TestFather这里面的虚表就只有~TestFather()这一个函数,使用虚函数代表会增加一个指针的内存开销
4. 默认的析构函数
当我们不定义虚构函数的时候,编译器会默认生成一个什么都不做的析构函数,但是注意了默认生成的析构函数就是普通函数不是虚函数!!!因为虚函数会带来额外开销,c++追求的是速度
5. 纯虚构析构函数
就是纯虚函数加上析构函数,一般我们把函数设置纯虚函数都是不想这个类实例化,抽象出来的顶层父类,并且这个纯虚函数不能实现。但是在纯虚析构这里不同
代码
#include <iostream>
class TestFather{
public:virtual ~TestFather() = 0;
};
TestFather::~TestFather() {std::cout << "~TestFather()" << std::endl;
}class TestChild : public TestFather {
public:~TestChild() {std::cout << "~TestChild()" << std::endl;}
};int main() {TestFather* p = new TestChild();delete p;
}//结果和上面的相同
6. 总结:
明确你的类会不会被继承,当作基类使用,把类的析构函数都设置为虚函数和不设置为虚函数都是不好的
1.如果你的类会被继承,当作基类,那么一定要把基类析构函数设置为虚函数
2.如果你的类不会被继承,单纯的类,那么不需要把析构函数设置为析构函数,因为会浪费空间,多一个虚表指针
相关文章:

Roberts 边缘检测
#include <opencv2/opencv.hpp> // roberts算子实现 cv::Mat roberts(cv::Mat srcImage) {cv::Mat dstImage srcImage.clone();int nRows dstImage.rows;int nCols dstImage.cols;for (int i 0; i < nRows - 1; i){for (int j 0; j < nCols - 1; j){// 根据公…

vector、map删除当前记录
map<string, string> sMap; map<string, string>::iterator iter; for(iter sMap.begin();iter ! sMap.end();/* iter */) {sMap.erase(iter); }注意下列错误表达:1. for(iter sMap.begin();iter ! sMap.end(); iter ) {sMap.erase(iter); } 错误原因…

1-2 postman工具简介
postman提供了一个多窗口和多选项卡页面用于发送和接受请求,postman努力保持整洁和灵活,提供更多的空间,满足用户的需要。他很简单,能满足大部分接口的测试,性价比特别高。如图所示: 1.侧边栏 postman的侧边…

【C++】重载运算符(一)
1.1 重载运算符特点 重载运算符本质上是一次函数调用 除了operator() 运算符调用外,其他重载运算符不能含有默认参数。 当重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数(显式)的参数数量比运算对象少一个。…

javaScript的调试(二)
2019独角兽企业重金招聘Python工程师标准>>> 一、Firebug Firebug是Firefox浏览器的调试工具,只要我们在Firefox中安装了Firebug应用,就可以按F12或右击鼠标开启调试 那么我们就先来看一下如何在Firefox中安装了Firebug应用,一图剩…

Prewitt 边缘检测
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include "opencv2/imgproc/imgproc.hpp" #include <iostream> // prewitt算子实现 cv::Mat prewitts(cv::Mat img, bool verFlag false) {img.convertTo(img, CV_32FC…

[swift 进阶]读书笔记-第十一章:互用性 C11P1 实践:封装 CommonMark
第十一章:互用性 Interoperability 前言: swift 的最大优点就是与C 或者 OC 混编的时候稳的一匹 本章主要讲了swift和C之间的一些知识点。 11.1 实践:封装 CommonMark Hands-On: Wrapping CommonMark 这一小节更像是一个教程。教你如何封装C语言中的Comm…

【Cmake】Cmake学习记录
Cmake学习记录 1.1 常例 add_library(gen_reference_infogen_reference_info/gen_reference_info.hgen_reference_info/gen_reference_info.cc ) target_link_libraries(gen_reference_infoparamsimage_preprocessorcenter_extractorremapperdescriptor_generator${OpenCV_LI…

MySQL(三)用正则表达式搜索
正则表达式是用来匹配文本的特殊的串(字符集合),将一个模式(正则表达式)与一个文本串进行比较; 所有种类的程序设计语言、文本编辑器、操作系统等都支持正则表达式,正则表达式用正则表达式语言来…

计算梯度幅值与方向
Mat magX Mat(src.rows, src.cols, CV_32F); Mat magY Mat(src.rows, src.cols, CV_32F); Sobel(image, magX, CV_32F, 1, 0, 3); Sobel(image, magY, CV_32F, 0, 1, 3); // 计算斜率 Mat slopes Mat(image.rows, image.cols, CV_32F); divide(magY, magX, slopes); // 计…

好程序员web前端技术分享媒体查询
为什么80%的码农都做不了架构师?>>> 好程序员web前端技术分享媒体查询 什么是媒体查询 媒体查询可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其设定CSS样式,媒体查询由媒…

【C++】重载运算符(二)
1.4 下标运算符p501 下标运算符必须是成员函数,表示容器的类通常可以通过容器中的位置访问元素,定义下标运算符operator[]一个包含下标运算符的类,通常,定义2个版本:一个返回普通引用,另一个是类的常量成员…
手动建库11.2.0.4
环境: oracle11.2.0.4 redhat6.2 在上篇文章中,我们只安装了oracle,还没有建立实例,本篇文章就来介绍如果手动建立实例。 1.创建密码文件(password file)----非必要 cd $ORACLE_HOME/dbs/ 查看是否有init.o…

滞后阈值边缘连接
// 边缘连接 void followEdges(int x, int y, Mat &magnitude, int tUpper,int tLower, Mat &edges) { edges.at<float>(y, x) 255; for (int i -1; i < 2; i) {for (int j -1; j < 2; j) {// 边界限制if((i ! 0) && (j ! 0) && (…

《复联4》的这波操作,其实是在灭 bug
前方涉及剧透,请谨慎阅读!!!前方涉及剧透,请谨慎阅读!!!前方涉及剧透,请谨慎阅读!!!↓↓↓Q1:您是否看了《复联4》?A、已看…

【C++】容器与继承
容器与继承 Exercise 15.28: Define a vector to hold Quote objects but put Bulk_quote objects into that vector. Compute the total net_price of all the elements in the vector. Exercise 15.29: Repeat your program, but this time store shared_ptrs to objects…

1.3 使用jmeter进行http接口测试
来源: http://www.cnblogs.com/alisapan/p/6150309.html 此篇纯是搬运记载。。 一、测试需求描述 1、 本次测试的接口为http服务端接口 2、 接口的主要分成两类,一类提供给查询功能接口,一类提供保存数据功能接口,这里我们举例2个…

opencv 自带库Canny边缘检测
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" int main( ) {// 读取源图像并转化为灰度图像cv::Mat srcImage cv::imread("..\\images\\flower.jpg",0);// 判断文件是否读入正确if( !srcImage.data ) retur…

git branch
git basic branch git branch <branchName>#create branch git branch --list#show branch list, git checkout <branchName>#choose branch,HEAD is pointer of the current branch last commit 复制代码create a file in branch 0.0.1,then checkout master ,mer…

读书笔记 effective c++ Item 5 了解c++默认生成并调用的函数
1 编译器会默认生成哪些函数 什么时候空类不再是一个空类?答案是用c处理的空类。如果你自己不声明,编译器会为你声明它们自己版本的拷贝构造函数,拷贝赋值运算符和析构函数,如果你一个构造函数都没有声明,编译器同样…

git tag学习记录(二)
文章目录1. git 工原理示意2. git tag记录2.1 git tag查看已有tag列表2.2 git tag标记当前分支上的 tag信息为-a v1.5.4 -m(给指定的commit打Tag)2.3 git push origin v1.5.4推送上一步打tag的分支到远程1. git 工原理示意 工作流程 TortoiseGit 2. g…

最小矩形与圆生成
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; int main() {cv::Mat img(500, 500, CV_8UC3);// 随机生成因子RNG& rng theRNG();for (;;){i…

详解微信域名防封的方法以及检测等工具的技术原理
微信域名完全防封是绝对不可能的,这是必须明确的,曾经有人打折《不死域名》的概念,它不是不死,是稍微命长一点,在推广上成本更低一下,效果更好一些,主要的技术原理是利用了腾讯云的域名安全联盟…

贝叶斯定理——数学之美
1.贝叶斯定理 1.1 定义:描述在已知一些条件下,某事件的发生概率 贝叶斯定理是关于随机事件A和B的条件概率的一则定理。 1.2 公式理解 P(x∣y)P(x)P(y∣x)P(y)P(x|y) \frac{ P(x)P(y|x)}{P(y)}P(x∣y)P(y)P(x)P(y∣x) 其中x以及y为随机事件ÿ…

HUST 1586 数字排列
1586 - 数字排列 时间限制:1秒 内存限制:128兆 91 次提交 36 次通过 题目描述现有n个k位的数字,你的任务是重新安排数字每一位的位置,使得重新安排后这n个数字中最大的数字和最小的数字之差的绝对值最小,对于每一位的调…

最小矩形与圆生成1
#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; // 计算外接矩形与圆轮廓…

kettle-核心概念
转载于:https://www.cnblogs.com/LXL616/p/10836183.html

adb调试命令小结
adb调试命令 adb 连接android设备 adb connect 192.168.103.246 connected to 192.168.103.246:5555 sunsun:~/workspace/deptrum$ adb connect 192.168.103.246:5555 already connected to 192.168.103.246:5555 sunsun:~/workspace/deptrum$ adb shell tb8788p1_64_bsp_wxp…

github创建本地库后关联远程库
在进行新项目开发时,有时候并不一定先创建远程库,而是先在本地将项目创建,到一定阶段后再与远程库关联。下面步骤解决本地库与远程库在这种情形。 1. 初始化本地库,既然项目已经创建了,相信这个也已经知道了。 git ini…

mysql以及mysql bench安装教程
首先,我们需要去官网下载mysql(这里以下载) 1 2 3 4 5 下载好了自己好了之后,点击安装好的东西出现如下界面: 1、接受使用条款并点击next 2、点击custom,可以根据个人习惯进行安装 3、这里来是需要安装的一…