博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++学习笔记 -- 虚析构函数与纯虚析构函数
阅读量:6852 次
发布时间:2019-06-26

本文共 2561 字,大约阅读时间需要 8 分钟。

开始学C++了,所以又重拾以前学习过的相关概念…

析构函数是当一个对象的生命周期结束时,会自动执行析构函数。

析构函数的定义:

#ifndef __A_H__ #define  __A_H__ class A {
public: A(void); A(int a, int b); ~A(void); //析构函数 private: int a; int b; int c; }; #endif

虚析构函数与纯虚析构函数的定义(假定类名为A):

#ifndef __A_H__ #define  __A_H__ class A {
public: A(void); A(int a, int b); virtual ~A(void); //虚析构函数 private: int a; int b; int c; }; #endif
#ifndef __A_H__ #define  __A_H__ class A {
public: A(void); A(int a, int b); virtual ~A(void) = 0; //纯虚析构函数 }; #endif

其中定义了纯虚函数后,类A就成为了“抽象类”,它是不能有实例对象的。否则会报错:

“A”: 不能实例化抽象类

由于下列成员:

“A::~A(void)”: 是抽象的

一个类维护一个虚函数相关的表--vtable(__vfptr指向它),函数声明前面包含关键字“virtual”的函数,就会创建一个指向该函数的指针(函数指针)被存入vtable中。

虚函数表的作用是用来实现多态,但同时也带来了执行效率和额外内存空间的增加。

 

再来看虚析构函数,它所存在的意义:基类的指针指向派生类对象,用基类的指针删除派生类对象。

#include 
using namespace std; class A {
public: A() {
cout <<"A..."<

输出:

A…

B…

~A…

派生类的析构函数未被调用,为什么呢?

派生类继承自基类,那么基类就只会存在于派生类中,直到派生类调用析构函数后。

假定:基类的析构函数调用比派生类要早,会造成的一种情况就是类成员不存在了,而类本身却还在,但是类存在的情况下,类成员应该还存在。所以这就矛盾了,所以派生类的析构函数会先被调用,基类的析构函数再被调用。

修改一下代码:

#include 
using namespace std; class A {
public: A() {
cout <<"A..."<

输出:

A…

B…

~B…

~A…

仅仅只是在基类的析构函数前面加了一个“virtual”,使它成为“虚析构函数”了,这就是“虚析构函数”存在的意义 :)

 

析构函数的作用并不是删除对象,而是撤销对象占用内存之前完成的一些清理工作…

//=========================================

总结:如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,就不要定义虚析构函数了,因为它会增加一个虚函数表,使得对象的体积翻倍,还有可能降低其可移值性。

所以基本的一条是:无故的声明虚析构函数和永远不去声明一样是错误的。

当且仅当类里包含至少一个虚函数的时候,才去声明虚析构函数。

抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以在想要成为抽象类的类里声明一个纯虚析构函数。

 

定义一个函数为虚函数,不代表该函数未被实现,只是为了来实现多态。

定义一个函数为纯虚函数,才表示函数未被实现 ,定义它是为了实现一个接口,起一个规范作用。继承抽象类的派生类要实现这个函数…

 

看下面的代码,如何输出:

//A.h #ifndef __A_H__ #define  __A_H__ class A {
public: A(void); A(int a, int b); virtual ~A(void); virtual void numAdd() = 0; virtual void f(); void ff(); private: int a; int b; int c; }; #endif
//A.cpp #include "A.h" #include 
using namespace std; A::A(void) {
} A::A(int a, int b) {
this->a = a; this->b = b; cout<<"a:"<
<<" b:"<<
//B.h #ifndef __B_H__ #define  __B_H__ #include "a.h" class B :public A {
public: B(void); ~B(void); virtual void numAdd(); void f(); virtual void ff(); }; #endif
//B.cpp #include "B.h" #include 
using namespace std; B::B(void) {
} B::~B(void) {
cout<<"~B"<

main函数的定义:

//main() B b; A * a = &b; a->f(); a->ff(); return 0;

输出什么?

B::f()

A::ff()

//定义指向基类对象的指针a,当调用f()方法时,因为f为虚函数,所以调用了派生类的f(),输出B::f();

 

参考:

转载于:https://www.cnblogs.com/meteoric_cry/archive/2013/05/08/3067270.html

你可能感兴趣的文章
删除超长路径/超长文件名文件夹
查看>>
SIP简介
查看>>
C#学习(一)之hello,world
查看>>
C#学习(三)之类的浅析
查看>>
转---写一个网页进度loading
查看>>
Go循环语句
查看>>
使用jQuery.FileUpload插件和Backload组件裁剪上传图片
查看>>
python一中实现组合的方式
查看>>
[原创]牛刀小试-重构并实现邮件内容生成功能
查看>>
过滤器
查看>>
Android 控件使用
查看>>
linux关闭防火墙
查看>>
贪吃蛇源码
查看>>
杂谈篇:阅读优秀代码是提高开发人员修为的一种捷径
查看>>
jfreechart 实例
查看>>
gstreamer 10.5版本发布啦
查看>>
Android--控件属性汇总
查看>>
LeetCode算法题-Implement Queue Using Stacks(Java实现)
查看>>
spring 事务
查看>>
[转自知乎] 如何成为一个优秀的程序员,而不是一个优秀的码农?
查看>>