C++学习——构造函数,析构函数与虚函数关系

文章目录

    • 1.构造函数,析构函数可以为虚函数吗?
    • 2.析构函数和构造函数的作用?
    • 3.构造函数和析构函数调用顺序?
    • 4.类什么时候会调用析构函数?

1.构造函数,析构函数可以为虚函数吗?

构造函数不可以,析构函数可以

  1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的。问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。

  2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到相应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。

  3. 构造函数不须要是虚函数,也不同意是虚函数,由于创建一个对象时我们总是要明白指定对象的类型,虽然我们可能通过实验室的基类的指针或引用去訪问它但析构却不一定,我们往往通过基类的指针来销毁对象。这时候假设析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。

  4. 从实现上看,vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数从实际含义上看,在调用构造函数时还不能确定对象的真实类型(由于子类会调父类的构造函数);并且构造函数的作用是提供初始化,在对象生命期仅仅运行一次,不是对象的动态行为,也没有必要成为虚函数。

  5. 当一个构造函数被调用时,它做的首要的事情之中的一个是初始化它的VPTR。因此,它仅仅能知道它是“当前”类的,而全然忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码——既不是为基类,也不是为它的派生类(由于类不知道谁继承它)。所以它使用的VPTR必须是对于这个类的VTABLE。并且,仅仅要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR将保持被初始化为指向这个VTABLE, 但假设接着另一个更晚派生的构造函数被调用,这个构造函数又将设置VPTR指向它的 VTABLE,等.直到最后的构造函数结束。VPTR的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到更加派生类顺序的还有一个理由。可是,当这一系列构造函数调用正发生时,每一个构造函数都已经设置VPTR指向它自己的VTABLE。假设函数调用使用虚机制,它将仅仅产生通过它自己的VTABLE的调用,而不是最后的VTABLE(全部构造函数被调用后才会有最后的VTABLE)。

因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。

C++中基类采用虚析构函数是为了防止内存泄漏。
具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。
假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。
那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,C++中基类的析构函数应采用virtual虚析构函数。

#include<iostream>
using namespace std;class base {
public:base() {}virtual void print() {cout << "base function" << endl;}~base() {cout << "base析构函数" << endl;}    
};class derived :public base{
public:derived(){}virtual void print() {cout << "derived function" << endl;}~derived(){cout << "derived析构函数" << endl;}
};
int main()
{base* ptr = new derived;ptr->print();delete ptr;return 0;
}
derived function
base析构函数

基类构造函数没有定义为虚函数,所以delete ptr只调用了基类的析构函数,没有调用派生类的构造函数,造成内存泄露。

#include<iostream>
using namespace std;class base {
public:base() {}virtual void print() {cout << "base function" << endl;}virtual ~base() {cout << "base析构函数" << endl;}    
};class derived :public base{
public:derived(){}virtual void print() {cout << "derived function" << endl;}~derived(){cout << "derived析构函数" << endl;}
};
int main()
{base* ptr = new derived;ptr->print();delete ptr;return 0;
}
derived function
derived析构函数
base析构函数

2.析构函数和构造函数的作用?

构造函数只是起初始化值的作用

析构函数与构造函数的作用相反,用于撤销对象的一些特殊任务处理,可以是释放对象分配的内存空间
析构函数的特点:析构函数与构造函数同名,但该函数前面加~。 析构函数没有参数,也没有返回值,而且不能重载,在一个类中只能有一个析构函数。 当撤销对象时,编译器也会自动调用析构函数。 每一个类必须有一个析构函数,用户可以自定义析构函数,也可以是编译器自动生成默认的析构函数。一般析构函数定义为类的公有成员。

3.构造函数和析构函数调用顺序?

构造函数顺序

① 基类构造函数。如果有多个基类,则构造函数的调用顺序是某类在类派生表中出现的顺序,而不是它们在成员初始化表中的顺序。

② 成员类对象构造函数。如果有多个成员类对象则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序。

③ 派生类构造函数。

析构函数顺序

① 调用派生类的析构函数;

② 调用成员类对象的析构函数;

③ 调用基类的析构函数。

4.类什么时候会调用析构函数?

  1. 对象生命周期结束,被销毁时;

  2. delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;

  3. 对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

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

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

相关文章

军事大脑的构建对未来战争的影响

前言&#xff1a;本文是我与军事科学院的赵蔚婷,王婉两位老师在2020年4月发表的一篇论文&#xff0c;首发在《中国科技论文在线》&#xff0c;是将互联网大脑模型与军事领域结合&#xff0c;形成军事大脑和军事超级智能的概念体系&#xff0c;重点提出军事神经元和军事云反射弧…

00001-整数倒置-Java-leetcode-要考虑到溢出问题

leetcode-整数倒置 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problems/reverse-integer 著作权归领扣网络所有。商业转载请联系官方授权&#xff0c;非商业转载请注明出处。给出一个 32 位的有符号整数&#xff0c;你需…

size - 列出段节大小和总共大小

总览 (SYNOPSIS) size[-A|-B|--formatcompatibility] [--help] [-d|-o|-x|--radixnumber] [--targetbfdname] [-V|--version] objfile...描述 (DESCRIPTION) GNU 的 size 程序 列出 参数列表 objfile 中, 各 目标文件(object) 或 存档库文件(archive) 的 段节(section)大小 ---…

C++学习——默认构造函数

默认构造函数在这篇博客中已经写得很明白。 https://blog.csdn.net/bear_n/article/details/72798301 文章目录1.什么是默认构造函数&#xff1f;2.什么情况会自动生成默认构造函数&#xff0c;即编译器生成默认构造函数&#xff1f;1.什么是默认构造函数&#xff1f; 默认构造…

斯坦福抢开“元宇宙”第一课,上起来还真不便宜

过去半个世纪&#xff0c;斯坦福教给学生的技术&#xff0c;促成了硅谷的诞生&#xff1b;而为了将来的 Web3 时代&#xff0c;斯坦福也已经做好了准备。来源&#xff1a; 硅星人文&#xff1a;杜晨 编辑&#xff1a;VickyXiao今年10月底&#xff0c;硅谷顶级科技公司 Facebo…

00002-两数之和-leetcode-1.暴力法(枚举法),2.哈希表法,目前更新了枚举法

两数之和 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problems/two-sum 著作权归领扣网络所有。商业转载请联系官方授权&#xff0c;非商业转载请注明出处。 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在…

c++ 字符串转数字

#字符串转整数 string ss"-99"; cout<< stoi(ss)<<endl; 转载于:https://www.cnblogs.com/sea-stream/p/11100398.html

C++学习——抽象类

文章目录1.抽象类1.1 什么是抽象类&#xff1f;1.2 抽象类的作用?1.3 使用抽象类时注意2.抽象基类为什么不能创建对象&#xff1f;1.抽象类 1.1 什么是抽象类&#xff1f; 带有纯虚函数的类为抽象类 1.2 抽象类的作用? 抽象类的主要作用是将有关的操作作为结果接口组织在一个…

00003-回文数的判定-leetcode-解法不唯一,1.reverse最简单,2.数学方法很有意思

回文数的判定 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problems/palindrome-number 著作权归领扣网络所有。商业转载请联系官方授权&#xff0c;非商业转载请注明出处。 判断一个整数是否是回文数。回文数是指正序&…

加拿大工程院院士于非:互联—— 从质量、能源、信息到智能

来源&#xff1a;AI科技评论整理&#xff1a;莓酊编辑&#xff1a;青暮2021年12月9日&#xff0c;第六届全球人工智能与机器人大会&#xff08;GAIR 2021&#xff09;在深圳正式启幕。140余位产学领袖、30位Fellow聚首&#xff0c;从AI技术、产品、行业、人文、组织等维度切入&…

常用命令之------ln

当我们需要在不同的目录&#xff0c;用到相同的文件时&#xff0c;我们不需要在每一个需要的目录下都放一个必须相同的文件&#xff0c;我们只要在某个固定的目录&#xff0c;放上该文件&#xff0c;然后在 其它的目录下用ln命令链接&#xff08;link&#xff09;它就可以&…

C++学习——继承

文章目录1.C中类成员的访问权限和继承权限问题2.多继承的优缺点3. 继承机制中对象之间如何转换4.组合与继承优缺点1.C中类成员的访问权限和继承权限问题 三种访问权限 public:用该关键字修饰的成员表示公有成员&#xff0c; 该成员不仅可以在类内可以被访问&#xff0c;在类外…

00004-括号匹配问题-牛客网-要考虑各种情况

括号匹配问题 链接&#xff1a;https://ac.nowcoder.com/acm/contest/3530/E 来源&#xff1a;牛客网 众所周知&#xff0c;佳爷是集训队最强&#xff0c;他经常喜欢鄙视集训队最菜的PC&#xff0c;这天他又来了&#xff0c;他丢给PC一道题目&#xff1a; 给你一个字符串&am…

2021年诺贝尔经济学奖评述:解决重大社会问题的自然实验因果框架

来源&#xff1a;集智俱乐部作者&#xff1a;诺奖委员会译者&#xff1a;邓宇昊 编辑&#xff1a;邓一雪 导语许多重大社会问题都涉及到因果分析。比如&#xff0c;接受更长时间的教育是否会让你未来的收入增加&#xff1f;提高最低工资对一个地方的就业会产生怎样的影响&…

C++学习——拷贝构造函数和移动构造函数

文章目录1.拷贝构造函数2.移动构造函数1.拷贝构造函数 拷贝构造函数&#xff0c;它是一种特殊的构造函数。它的作用就是用一个已经生成的对象来初始化另一个同类的对象。 当类中拥有指针类型的成员变量时&#xff0c;拷贝构造函数中需要以深拷贝&#xff08;而非浅拷贝&#xf…

spring学习笔记03-spring-DI-依赖注入详解(通过xml配置文件来配置依赖注入)

spring学习笔记03-spring-DI-依赖注入详解 1.概念 2.构造函数注入 3.set方法注入 4.集合的注入 需要被注入的实体对象 package com.itheima.service.impl;import com.itheima.service.IAccountService;import java.util.Arrays; import java.util.List; import java.util.Pr…

溯因推理:人工智能的盲点

来源&#xff1a;AI前线作者&#xff1a;Ben Dickson译者&#xff1a;Sambodhi策划&#xff1a;凌敏本文给当今人工智能界推崇深度学习的现象泼了冷水&#xff0c;指出了人工智能的盲点&#xff1a;溯因推理&#xff0c;并提醒人们不要忽视深度学习的种种问题&#xff0c;否则将…

Python Django项目部署 Linux 服务器

项目依赖: Linux Centos7 (阿里云轻量级服务器) Python 3.7.2 Django 2.2.1 restframework 3.9.4 mysql 5.7 1 安装 python3 到 Centos7&#xff0c; 先安装软件管理包和可能使用的依赖 yum -y groupinstall "Development tools" yum install openssl-devel bzip…

C++学习——C++中的四种类型转换

文章目录1.dynamic_cast2.const_cast3.3 static_cast3.4 reinterpret_cast1.dynamic_cast 用于动态类型转换。只能用于含有虚函数的类&#xff0c;用于类层次间的向上和向下转化。只能转指针或引用。向下转化时&#xff0c;如果是非法的对于指针返回NULL&#xff0c;对于引用抛…

终于,LoRaWAN成全球物联网标准!LoRa将拿下LPWAN领域50%市场?

来源&#xff1a;LoRa联盟官网等整理发布&#xff1a;物联网智库 不久之前&#xff0c;支持物联网低功耗广域网&#xff08;LPWAN&#xff09;LoRaWAN开放标准的LoRa联盟宣布&#xff0c;致力于“物联网和智慧城市及社区标准化”的国际电联电信标准化部门&#xff08;ITU-T&…