C++:this指针和构造与析构的运用

目录

一,this指针

二,构造函数

三,析构函数

四,析构与构造的调用


一,this指针

        首先,我们先观察以下类:

#include <iostream>
using namespace std;
class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;     
    int _month;    
    int _day;      
};
int main()
{
    Date d1, d2;
    d1.Init(2022, 1, 11);
    d2.Init(2022, 1, 12);
    d1.Print();
    d2.Print();
    return 0;
}

        对于上述类,有这样的一个问题: Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢? C++中是通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(即此类),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。如下图:

class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //void Print(Data* this),错误,不能显示的写实参和形参,里面默认就有this指针
    void Print()
    {
        //我们不能在形参中写,但是可以在类里面使用,因为默认有this指针
        cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;     
    int _month;    
    int _day;      
};

这里需要说明以下几个问题:

        1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。

        2. this指针只能在“成员函数”的内部使用。

        3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。

        4. this指针是“成员函数”第一个隐含的指针形参,而形参跟函数一样存储在栈区中,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。


二,构造函数

介绍:

        构造函数:在创建对象时,自动的进行初始化工作。语法:类名() {...}

        构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时,由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。

特征:

        1,构造函数的访问权限一般情况下要设置为public,设置为private将无法访问构造函数,导致建立类时自动访问将会出错。

        2,函数名必须与类名相同。

        3,没有返回值,也不写void。

        4,可以有参数,可以重载,可以有默认参数。

        5,创建对象时会自动调用一次,不能手工调用。

这里需注意以下几点:

        1,如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明。 

        2,构造函数的权限若设置为private将会将会出错,因为权限不可访问。      

        3,如果定义了许多类,构造函数将会按照先后顺序调用。      

默认构造函数:

        如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成,默认构造函数将会往对象中放入随机值。

        C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类 型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,而编译器生成的默认构造函数只会对自定类型成员调用它的默认构造函数,内置类型一般不做处理,但有些编译器会对其进行处理(这里建议都看成不处理),即只处理自定义类型,为解决这一问题,在C++11标准中,内置类型成员变量在类中声明时可以给默认值。

        内置类型是编译器自己定义的,所以一般都会自动给它们初始化,但内置类型不知是如何实现的,所以不会处理,需要默认构造函数处理。

样例示范:                       

#include <iostream>
using namespace std;
class Date
{
public://设置为公有权限,否则相当于建立时将会出错
    // 1.无参构造函数
    Date()
    {}
    // 2.带参构造函数
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1; // 调用无参构造函数
    Date d2(2015, 1, 1); // 调用带参的构造函数
    Date d3();//函数的声明,声明了d3函数,该函数无参,返回一个日期类型的对象
    return 0;
}


三,析构函数

析构函数:在销毁对象前,自动的完成清理工作,即在对象生命周期结束时将会清理空间资源。

特征:

        1,析构函数的函数名是在类名前加上一个符号 ‘~’。

        2,析构函数无参数且无返回值类型。

        3,一个类中只能有一个析构函数,若没有自己定义,系统会自动生成一个默认析构函数。

        4,在对象的生命周期结束时,系统将会自动调用析构函数。

注意:

        1,由于析构函数没有参数,因此此函数不支持重载。

        2,析构函数的权限设置跟构造函数的设置一样,一般都要设置为public。

        3,类的析构函数调用一般按照构造函数调用的相反顺序进行调用,即倒序,但要注意static和全局变量的情况,存储静态区的将会在整个代码结束后才会调用。

        4,默认析构函数跟默认构造函数一样,只对自定义类型成员处理,即自定义类型成员会去调用他的析构函数,而内置类型成员不做任何处理。

        5,析构函数只能释放该对象本身所占用的空间,但对象内部所指向的内存空间或其它空间没有被释放,最终将会造成内存泄漏。

        6,由第2条可知,如果类中没有申请资源时,析构函数可不写,直接使用编译器生成的默认析构函数即可。因为当对象的生命周期结束后空间就自动销毁了,也就还给操作系统了,但是如果在堆区中开辟了空间就需要在析构函数中自己完成清理工作。

样例示范一:

class Time
{
public:
    //首先权限设置必须为public,否则结束时将不可调用,将会出错
    //其次,类对象的成员中没有在堆区中占用空间,可不写析构函数

    ~Time()
    {
        cout << "~Time()" << endl;
    }
private:
    int _hour;
    int _minute;
    int _second;
};

样例示范二:

class Stack
{
public:
    Stack(size_t capacity = 3)
    {
        _array = (int*)malloc(sizeof(int) * capacity);
        _capacity = capacity;
        _size = 0;
    }
    void Push(int data)
    {
        _array[_size] = data;
        _size++;
    }
    //首先权限要设置为public
    //动态开辟空间,需要在析构函数中释放动态空间

    ~Stack()//析构函数中不能有参数
    {
        if (_array)
        {
            free(_array);
            _array = NULL;
            _capacity = 0;
            _size = 0;
        }
    }
private:
    int* _array;
    int _capacity;
    int _size;
};


四,析构与构造的调用

构造函数的调用:

        当一个程序开始定义类时,程序就自动进入了此类中的构造函数阶段,构造完了之后系统就会自动往下运行,当又遇到一个类时,又将进入此类中的构造函数,也就是说当存在多个类定义时,系统会按照从前往后的顺序调用此类的构造函数。

析构函数的调用:

        析构函数是在一个函数即将结束时才会开始调用,一般情况下,调用的顺序是跟析构函数的调用顺序相反,即倒序,但是,当存在类似于static类时的情况就很不一样,因为此种情况是存储在系统的静态空间中,而静态空间不会随着函数栈帧的销毁而销毁,只有当一整个程序完毕之后才会系统才会做回收。

        上图中的构造函数的调用顺序为C,A,B,D。

代码演示:

#include <iostream>
using namespace std;
int i = 0;
class Data2
{
public:
    Data2()
    {
        i++;
        cout << "2构造中的i = " << i << endl;
    }
    void Print()
    {
        i++;
        cout << "2类输出中的 i = " << i << endl;
    }
    ~Data2()
    {
        i++;
        cout << "2析构中的i = " << i << endl;
    }
};
class Data1
{
public:
    Data1()
    {
        i++;
        cout << "1构造中的i = " << i << endl;
    }
    void Print(Data2 p)//类传入,当此函数结束时,会调用Data2类中的析构,即销毁形参中的类
    {
        i++;
        cout << "1类输出中的 i = " << i << endl;
    }
    ~Data1()
    {
        i++;
        cout << "1析构中的i = " << i << endl;
    }
};
int main()
{
    Data1 a;//调用Data1中的构造
    Data2 b;//调用Data2中的构造
    a.Print(b);
    cout << endl;
    //当系统运算到此步时就要开始调用析构函数了,在析构函数中,先析构Data2类型,再析构Data1的类型
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HCIA-hybrid经典小实验

hybrid经典小实验 实验拓扑配置实现SW1SW2 配置验证PC1-PC3 不能通信PC1-PC2 正常通信其他自行测试 实验拓扑 配置实现 SW1 sysname SW1 # undo info-center enable # vlan batch 10 20 30 # interface Ethernet0/0/1 //接口发送该vlan-id的数据帧时&#xff0c;不剥离帧中的…

JavaSE 类与对象

前言 我们之前学的都是面向过程&#xff0c;面向过程研究的是对单个对象的一种方法实现过程&#xff0c;比如求一个数的阶乘&#xff0c;强调的是怎么实现这个方法的过程&#xff0c;但对我们以后来说&#xff0c;如果想要应用到更广的层面&#xff0c;不能只是学习一个方法的…

JMeter 常见函数讲解

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;加入1000人软件测试技术学习交流群&#x1f4e2;资源分享&#xff1a;进了字节跳动之后&#xff0c;才…

宠物社区系统宠物领养小程序,宠物救助小程序系统多少钱?

当前很多的宠物被抛弃和虐杀&#xff0c;它们没有选择权&#xff0c;我们强制性的把狗带进人类的生活中&#xff0c;然后又无情的抛弃&#xff0c;让它们无家可归&#xff0c;变成流浪狗&#xff0c;它们做错了什么&#xff1f;流浪动物被主人遗弃之后居无定所&#xff0c;时刻…

C语言【趣编程】我们怎样便捷输出空心的金字塔

目录 1问题&#xff1a; 2解题思路&#xff1a; 3代码如下&#xff1a; 4代码运行结果如下图所示&#xff1a; 5总结&#xff1a; r如若后续有不会的问题&#xff0c;可以和我私聊&#xff1b; 1问题&#xff1a; 2解题思路&#xff1a; 方法&#xff1a;找规律&#xff0…

AI系统ChatGPT源码+详细搭建部署教程+AI绘画系统+支持GPT4.0+Midjourney绘画+已支持OpenAI GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

2023/11/11

1. 实现字体渐变色 html <div class"gradient">实现字体渐变色 </div>css .gradient {display: inline-block;font-weight: 800;font-size: 40px;color: #fff;background: linear-gradient(90deg, #f00 0%, #000 50%, #00f 100%);background-clip: bo…

积分上限函数

定积分的形式 a&#xff1a;积分下限 b&#xff1a;积分上限 定积分的值与积分变量无关 积分上限函数的形式 x&#xff1a;自变量 t&#xff1a;积分变量 积分上限是变量&#xff0c;积分下限是常数 定积分的几何意义 x轴所围成面积 x轴以上面积为正 x轴以下面积为负 积分…

Linux学习教程(第一章 简介)4

第一章 简介 十一、Linux的主要应用领域有哪些? Linux 似乎在我们平时的生活中很少看到,那么它应用在哪些领域呢?其实,在生活中随时随地都有 Linux 为我们服务着。 1、网站服务器 用事实说话!访问国际知名的 Netcraft 网站 http:// www.netcraft.com,在 "Whats …

数据分析实战 | 泊松回归——航班数据分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 一、数据及分析对象 CSV文件&#xff1a;o-ring-erosion-only.csv 数据集链接&#xff1a;https://download.csdn.net/download/m0_7…

网络安全基础之php开发文件上传的实现

前言 php是网络安全学习里必不可少的一环&#xff0c;简单理解php的开发环节能更好的帮助我们去学习php以及其他语言的web漏洞原理 正文 在正常的开发中&#xff0c;文件的功能是必不可少&#xff0c;比如我们在论坛的头像想更改时就涉及到文件的上传等等文件功能。但也会出…

Leetcode刷题详解——单词搜索

1. 题目链接&#xff1a;79. 单词搜索 2. 题目描述&#xff1a; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的…

基于ubuntu 22, jdk 8x64搭建图数据库环境 hugegraph--google镜像chatgpt

基于ubuntu 22, jdk 8x64搭建图数据库环境 hugegraph download 环境 uname -a #Linux whiltez 5.15.0-46-generic #49-Ubuntu SMP Thu Aug 4 18:03:25 UTC 2022 x86_64 x86_64 x86_64 GNU/Linuxwhich javac #/adoptopen-jdk8u332-b09/bin/javac which java #/adoptopen-jdk8u33…

开源软件有漏洞,作者需要负责吗?是的——作者责任与社会共同关注开源

近日&#xff0c;禅道作者在开源中国发布的一篇文章引起了众多同行的围观&#xff0c;原因是该文章分享了一个开源协议在中国面临的 bug&#xff01;开源软件许可协议通常会表明作者不对用户使用该开源软件所造成的任何问题负责。但是这种条款&#xff0c;在中国&#xff0c;是…

Labview的分支判断

和其他的编程语言一样的。都会有switch,case, if ,else; 再combo box中实现 再后台程序中对应的写上逻辑就好了。

Android 解决CameraView叠加2个以上滤镜拍照黑屏的BUG (一)

1. 前言 这段时间&#xff0c;在使用 natario1/CameraView 来实现带滤镜的预览、拍照、录像功能。 由于CameraView封装的比较到位&#xff0c;在项目前期&#xff0c;的确为我们节省了不少时间。 但随着项目持续深入&#xff0c;对于CameraView的使用进入深水区&#xff0c;逐…

Linux系统初步了解

Linux系统由4个主要部分组成&#xff1a;内核、Shell、文件系统和应用程序。 本专题主要是围绕这四个来展开的。 POSIX&#xff08;可移植操作系统接口&#xff09;定义了操作系统应该为应用程序提供的标准接口&#xff0c;其意愿是获得源码级别的软件可移植性。所以Linux选择…

elemenui的Upload上传整合成数组对象

1. 普通直接上传 <el-upload action"" :before-upload"doBeforeUpload"><el-button type"success" size"mini">导入</el-button></el-upload> methods:{doBeforeUpload(file) {let reader new FileReader(…

Postman基本页面和请求/响应页签介绍

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 一、Postman的界面介绍 Home主页、Workspace工作空间、Collections集合、Environments环境变量、Mock Server虚拟服务器、Mo…

GEE:计算有效像素占比(统计有效像素数量、像素总数)

作者:CSDN @ _养乐多_ 在GEE中进行遥感数据处理的时候,经常会由于去云,导致影像出现空洞,只有部分像素可用,或者在进行特殊处理时,只对有效像素进行处理,但是我们不知道有效像素数量和占比,无法对结果做出准确的分析。这个时候就需要统计有效像素数量占比。 本文记录…
最新文章