虚析构函数

需要虚析构函数的原因:

首先看一下这段代码:

#include <iostream>
using namespace std;class A {
private: int *a;
public: A() { a = new int; cout << "A::A() is called.\n"; }~A() { delete a; cout << "A::~A() is called.\n"; }void print() { cout << "A::print() is called.\n"; }
};class B : public A {
private: int *b;
public:B() { b = new int; cout << "B::B() is called.\n"; }~B() { delete b; cout << "B::~B() is called.\n"; }void print() { cout << "B::print() is called.\n"; }
};int main() {A * p = new B();delete p;return 0;
}

说明:

  1. 可以将子类指针(或引用)赋值给父类指针(或引用)
  2. 在构造子类对象时,会先构造父类对象,再构造对应的子类对象部分
  3. new新空间时,之后必须进行delete,否则会造成内存泄漏

代码运行结果:

A::A() is called.
B::B() is called.
A::~A() is called.

可以发现仅对B进行了构造,而没有进行析构,因此可能会造成内存泄漏。为了避免这一问题的发生,就需要引出一个新的知识点——虚析构函数。

虚析构函数

析构函数虚函数我们已经熟悉了,那么如何实现虚析构函数呢?顾名思义,只要把虚函数与虚构函数结合起来就行了。例如:

class A {
public: A();  //构造函数virtual ~A();  //虚析构函数virtual void print();  //虚函数
};

可见,只要在原来的析构函数声明前加上virtual关键字就形成了虚析构函数。由此可以修改代码为:

#include <iostream>
using namespace std;class A {
private: int *a;
public: A() { a = new int; cout << "A::A() is called.\n"; }virtual ~A() { delete a; cout << "A::~A() is called.\n"; }  //添加virtual关键字,形成虚析构函数void print() { cout << "A::print() is called.\n"; }
};class B : public A {
private: int *b;
public:B( int *t ) { b = new int; cout << "B::B() is called.\n"; }~B() { delete b; cout << "B::~B() is called.\n"; }void print() { cout << "B::print() is called.\n"; }
};int main() {int x = 1;A * p = new B( &x );delete p;return 0;
}

运行结果:

A::A() is called.
B::B() is called.
B::~B() is called.
A::~A() is called.

此时各个对象都会调用析构函数,问题也就解决了。

仅在基类声明为虚析构函数原因:

同普通虚函数一样,它的实现也需要维护一个虚函数表,在此基础上来根据对象类型来选择使用哪个虚构函数。以上面代码为例,由于p实际指向的是B类型的对象,又由于在基类声明了虚析构函数,因此会根据类型选择调用B的析构函数,同时由于在析构派生类时也会自动调用基类的析构函数,所以最终所有的对象都会被析构。

(并不是所有c++类都应该将析构函数设置为virtual。只有具有virtual函数的多态基类(或者其它想当base class的类)才应该将析构函数设置为virtual,对于普通的类则无必要。因为虚函数的实现要求对象携带额外信息,也就是维护一个指向虚函数表的指针vptr(virtual table pointer),vptr指向虚函数表vtbl(virtual table)。当调用一个对象的虚函数时,就会通过vptr找到vtbl,在vtbl中寻找正确的函数指针调用。由于vptr的加入,导致对象大小增加。所以对于非多态基类,没必要将析构函数声明为virtual以带来额外负担。 ——引用自https://www.cnblogs.com/zhuyf87/archive/2013/03/12/2955058.html)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/381931.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于编写流程的一些经验

关于编写流程的一些经验 各位同行有时编写较多的流程。在很多情况下需要修改其他同事的流程。在修改的过程中需要了解流程的结构、看懂原流程各部分编写的情况 &#xff0c;了解每个变量存放的内容。但由于在编写过程中会不断的修改增加流程&#xff0c;所以有时有些地方的情况…

CodeForces 501B——Misha and Changing Handles

题意&#xff1a;给定一些姓名的原来姓名和修改后的名字&#xff0c;由于一个名字可以被修改多次&#xff0c;所以求所有用户的初始姓名和当前姓名。 思路&#xff1a;暴力。数据量很小&#xff0c;对于每次修改直接判断其是否有原来的名字即可&#xff0c;有的话更新&#xff…

静态多态 动态多态

一. 静态多态 1. 何为静态多态&#xff1f; 又称编译期多态&#xff0c;即在系统编译期间就可以确定程序将要执行哪个函数。例如&#xff1a;函数重载&#xff0c;通过类成员运算符指定的运算。 2. 示例代码 函数重载示例&#xff1a; class A { public:A() {}A( int x ) …

来几个FUNNY PICS,让大家笑一笑!

点解蜡笔小新成日都可以甘猥琐&#xff5e;转载于:https://www.cnblogs.com/hdclub/archive/2005/04/26/145761.html

uva 10954——Add All

<p>题意&#xff1a;给定一个序列&#xff0c;然后从中选择两个数&#xff0c;相加后放入原来的序列&#xff0c;消耗的费用为两个数 的和&#xff0c;问最小的代价。</p><p></p><p>思路&#xff1a;贪心。用优先队列维护&#xff0c;每次取得时…

jsoncpp学习笔记

jsoncpp 一. json基础 类型&#xff1a; 1. Json::Value为主要数据类型&#xff1b; 2. Json::Reader将文件流或字符串创解析到Json::Value中&#xff0c;主要使用parse函数&#xff1b;3. Json::Writer&#xff1a;与JsonReader相反&#xff0c;将Json::Value转换成字符串流…

Together与Visual.Studio.NET的结合使用(三)

通用选项&#xff1a; 图二十九&#xff1a;通用选项 Delete confirmation&#xff1a;此选项定义当你删除一个元素的时候是否需要进行确认。 Automatically enable Together VS.NET support for opened projects&#xff1a;当打开一个已存在的项目时&#xff0c;是…

uva 1152 ——4 Values whose Sum is 0

题意&#xff1a;给定4个n元素集合&#xff0c;要求从每个集合中选择一个数&#xff0c;使得ABcd0&#xff0c;问存在多少种方法。 思路&#xff1a;枚举hash判断。直接枚举4次方的算法会超&#xff0c;那么只需要枚举ab&#xff0c;然后在cd的和中查找等于-&#xff08;ab&…

c++ STL 全排列

在c的STL中有函数可以直接对数组元素进行全排列&#xff0c;即next_permutation和pre_permutation&#xff0c;这两个函数都可以实现全排列&#xff0c;只是排列的顺序不同&#xff0c;next_permutation作用为向后排序&#xff0c;而pre_permutation作用为向前排序。 需要头文…

创建下标为1-10的整形数组

创建下标为1-10的整形数组 Array intArr Array.CreateInstance(typeof(int), newint[]{10}, newint[]{1}); posted on 2005-05-11 16:32 K3 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/sskset/archive/2005/05/11/153238.html

uva 1605 ——Building for UN

题意&#xff1a;给定n&#xff0c;让设计一个大楼&#xff0c;使得n个国家任意两个国家都相邻或上下层。 思路&#xff1a;由于题目中的限定很小&#xff0c;可以这样考虑&#xff0c;只设计两层&#xff0c;每层的第i行为同一个国家&#xff0c;第二层的所有第j列为同一个国家…

友元函数 友元类 友元成员函数

友元 一般来说&#xff0c;类内的私有数据是对外不可见的&#xff0c;但在有些情况下&#xff0c;我们需要在类外对该类的私有数据进行访问&#xff0c;这就需要用到一种新技术——友元&#xff08;friend&#xff09;&#xff0c;即在声明前添加关键字friend。 友元关系是单向…

uva 120——Stacks of Flapjacks

题意&#xff1a;一个非常有趣的问题&#xff0c;就是给一摞煎饼&#xff0c;然后从下面拿起来一张&#xff0c;然后把该张上面的所有馅饼反转&#xff0c;求最后使得馅饼从小到大的最小的步数。 思路&#xff1a;贪心。每次都把没排好序的最大数反转到最上面&#xff0c;然后在…

[Diary]我也要向菁儿检讨一下

看到了CS版&#xff0c;angel 因为没能按时参加聚会发的检讨贴&#xff0c;觉得我也有必要检讨一下。&#xff08;一&#xff09; 菁儿昨天大概很生气吧&#xff0c;前天下午本来答应和她昨天下午一起去参加CS版版聚的&#xff0c;因为学校里难得有一些聚会可以认识一些朋友&am…

继承与动态内存分配

继承与动态内存分配 在基类或派生类中含有指针时&#xff0c;要考虑内存分配情况&#xff08;new与delete&#xff09;&#xff0c;还要考虑在进行对象间赋值时指针隐藏的问题&#xff08;使用默认复制构造函数在析构时会造成原对象中的指针指向的内存空间被释放&#xff0c;为…

再谈VC++中ListControl排序[原创]

2005.01.05发表于blog.csdn.net/zxub  昨天做了ListControl中的排序功能&#xff0c;但是使用后&#xff0c;发现只有在第一次数据完全没排序的时候&#xff0c;排序才是正确的&#xff0c;仔细看了下排序用到的回调函数&#xff1a;  int CALLBACK CStaMDiag::CompareFunc…

uva 11572 ——Unique Snowflakes

题意&#xff1a;给定一个序列&#xff0c;然后在这个序列找到一个连续的串&#xff0c;使得串中没有重复的元素。 思路&#xff1a;单调队列。每次都把该在序列没出现的数加入到序列中&#xff0c;然后向后扫描找到最大的ans。 code&#xff1a; //#incllude <bits/stdc.h&…

使用.NET类库操作CSV文件

CSV文件&#xff0c;是指使用逗号对数据进行分割的文本数据文件。昨天有人提出了一个问题&#xff0c;就是怎么对CSV文件进行操作&#xff0c;并且给出了一个类的定义。我根据这个类定义实现了一个能够读些CSV文件的类。由于涉及到了字符串操作&#xff0c;为了提高查询、替换性…

uva 11054——Wine trading in Gergovia

题意&#xff1a;有n个村庄&#xff0c;每个村庄要么买酒&#xff08;&#xff09;&#xff0c;要么卖酒&#xff08;-&#xff09;&#xff0c;要求供需平衡&#xff0c;求最小代价&#xff08;代价k为把k个单位的酒运到相邻的村庄&#xff09;。 思路&#xff1a;贪心。可以把…

uva 1312——Cricket Field

题意&#xff1a;在w*h的方格内&#xff0c;找出一个最大的正方形&#xff0c;使得正方形内没有点&#xff08;可以在边界有点&#xff09;。 思路&#xff1a;枚举。正方形可以看作是矩形&#xff0c;只不过在取的时候取最短的那条边作为边长&#xff0c;那么枚举出短边最大的…