C++零碎记录(三)

news2024/12/25 9:29:21

作者:小王同学在积累
链接:https://www.zhihu.com/question/437657370/answer/1692846096
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

5. 构造函数和析构函数

5.1 构造函数和析构函数的作用

① 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

② 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

5.2 构造函数和析构函数的语法

① 构造函数语法:类名 () {}

1. 构造函数,没有返回值也不写void。
2. 函数名称与类名相同。
3. 构造函数可以有参数,因此可以重载。
4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次。

② 析构函数语法:~类名(){}

1. 析构函数,,没有返回值也不写void。
2. 函数名称与类名相同,在名称前加上符号。
3. 析构函数不可以有参数,因此不可以发生重载。
4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次。
#include <iostream>
using namespace std;
#include <string>

//对象的初始化和清理
//1、构造函数 进行初始化操作

class Person
{
public:  //无论是构造函数还是析构函数都是在public作用域下
    //1.1、构造函数
    //没有返回值 不用写void
    //函数名 与类名相同
    //构造函数可以有参数,可以发生重载
    //创建对象的时候,构造函数会自动调用,而且只调用一次
    Person()
    {
        cout << "Person 构造函数的调用" << endl;
    }

    /*
    如果你不写,编译器会自动创建一个,但是里面是空语句
    Person()
    {
        
    }
    */

    //1. 析构函数,,没有返回值也不写void。
    //2. 函数名称与类名相同,在名称前加上符号。
    //3. 析构函数不可以有参数,因此不可以发生重载。
    //4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次。
    ~Person()
    {
        cout << "Person 析构函数的调用" << endl;
    }
};

//构造和析构都是必须有的实现,如果我们自己不提供,编译器会提供一个空实现
void test01()
{
    Person p;  //创建对象的时候,自动调用构造函数
               //这个对象p是一个局部变量,是在栈上的数据,test01执行完,释放这个对象
}

int main()
{
    
    //方式一:
    test01();   // 析构释放时机在test01运行完前,test01函数运行完后,里面的对象就被释放了
    

    /*
    方式二:     //创建对象的时候,自动调用构造函数
    Person p;   //只有构造函数,没有析构函数,只有main函数结束完前,对象要释放掉了,才会调用析构函数
    */

    system("pause");

    return 0;

}

运行结果:

  • Person 构造函数的调用
  • Person 析构函数的调用
  • 请按任意键继续. . .

5.3 构造函数的分类及调用

① 两种分类方式:

1. 按参数分为:有参构造和无参构造。
2. 按类型分为:普通构造和拷贝构造。

② 三种调用方式:

1. 括号法
2. 显示法
3. 隐式转换法
#include <iostream>
using namespace std;

//1构造函数的分类及调用
//分类
//按照参数分类:无参构造(默认构造) 和 有参构造
class Person
{
public: 
    //构造函数  编译器默认的构造函数是无参的
    Person()
    {
        cout << "Person 无参构造函数的调用" << endl;
    }


    Person(int a)
    {
        age = a;
        cout << "Person 有参构造函数的调用" << endl;
    }

    //拷贝构造函数
    Person( const Person &p)  //用引用的方式传进来,不能改变原来的对象的属性,所以用const        
    {
        // 将传入的人人身上的所有属性,拷贝到我身上
        cout << "Person 拷贝构造函数的调用" << endl;
        age = p.age;
    }

    ~Person()
    {
        cout << "Person 析构函数的调用" << endl;
    }

    int age;
};

//调用
void test01()
{
    /*
    
    //1、括号法
    Person p1;       //默认构造函数调用
    Person p2(10);   //有参构造函数
    Person p3(p2);   //拷贝构造函数

    cout << "p2的年龄为:" << p2.age << endl;
    cout << "p3的年龄为:" << p3.age << endl;

    //注意事项1
    //调用默认构造函数的时候,不要加()。
    //下面这行代码,编译器会认为是一个函数的声明,像void func(),不会认为在创建对象。
    //Person p1();

    */

    /*
    * 
    //2、显示法
    Person p1;  //创建一个对象,这个对象调用的是无参构造
    Person p2 = Person(10); //有参构造  将匿名对象起了一个名称p2
    Person p3 = Person(p2); //创建一个对象,这个对象调用的是拷贝构造

    Person(10); //匿名对象 特点:当前行执行结束后,系统会立即回收匿名对象
    cout << "aaaa" << endl;  //通过打印时机可以得到:test还没结束,就运行析构函数了
    
    //注意事项2
    //不要利用拷贝构造函数 初始化匿名对象  编译器认为 Person(p3) 等价于 Person p3,
    //编译器会认为这是一个对象的声明,而上面已经有一个p3了,Person p3 = Person(p2);因此编译器认为重定义了       
    Person(p3);

    */
    
    //3、隐式转换法
    Person p4 = 10; //相当于 写了 Person p4 = Person(10);  调用有参构造
    Person p5 = p4; //调用拷贝构造

}
int main()
{
    test01();

    system("pause");

    return 0;

}

运行结果:

  • Person 有参构造函数的调用
  • Person 拷贝构造函数的调用
  • Person 析构函数的调用
  • Person 析构函数的调用
  • 请按任意键继续. . .

5.4 拷贝构造函数调用时机

① C++中拷贝构造函数调用时机通常有三种情况。

1. 使用一个已经创建完毕的对象来初始化一个新对象。
2. 值传递的方式给函数参数传值。
3. 以值方式返回局部对象。
#include <iostream>
using namespace std;

//拷贝构造函数调用时机

//1、使用一个已经创建完毕的对象来初始化一个新对象

//2、值传递的方式给函数参数传值

//3、值方式返回局部对象

class Person
{
public:
    Person()
    {
        cout << "Person 默认构造函数调用" << endl;
    }

    Person(int age)
    {
        m_Age = age;
        cout << "Person 有参构造函数调用" << endl;
    }

    Person(const Person& p)
    {
        m_Age = p.m_Age;
        cout << "Person 拷贝构造函数调用" << endl;
    }

    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }

    int m_Age;

};

//1、使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
    Person p1(20);
    Person p2(p1);

    cout << "p2的年龄为:" << p2.m_Age << endl;
}

//2、值传递的方式给函数参数传值
void doWork(Person p)
{

}

void test02()
{
    Person p;
    doWork(p);   //实参传给形参的时候,会调用拷贝构造函数,这个是值传递,是一个临时的副本
                 //拷贝出去的p和原来的p 不是一个p
}

//3、值方式返回局部对象
Person doWork2() //返回值类型为Person对象
{
    Person p1;   //局部对象
    cout << (int*)&p1 << endl;
    return p1;  //以值的方式返回一个拷贝的对象给外部,拷贝出一个对象p1'与原对象p1不一样,调用拷贝构造函数

    //程序运行结束,释放原p1,调用析构函数
}

void test03()
{
    Person p = doWork2(); //这里没有调用拷贝构造函数,直接用p接收拷贝对象p1’
    cout << (int*)&p << endl;

    //程序运行结束,释放拷贝的对象p1',调用析构函数
}

int main()
{
    //test01();	
    //test02();
    test03();

    system("pause");

    return 0;

}

运行结果:

  • Person 默认构造函数调用
  • 005DF904
  • Person 拷贝构造函数调用
  • Person 析构函数调用
  • 005DF9FC
  • Person 析构函数调用
  • 请按任意键继续. . .

5.5 构造函数调用规则

5.5.1 构造函数调用规则

① 默认情况下,C++编译器至少给一个类添加3个函数。

1. 默认构造函数(无参,函数体为空)
2. 默认析构函数(无参,函数体为空)
3. 默认拷贝构造函数,对属性进行值拷贝

② 构造函数调用规则如下:

1. 如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造。
2. 如果用户定义拷贝函数,C++不会再提供其他构造函数。

③ 巧记法,如下图所示,如果定义中间的,上面的就默认不定义了,下面的默认定义。

5.5.2 调用定义的拷贝构造函数

#include <iostream>
using namespace std;

//构造函数的调用规则
//1、创建一个类,C+=编译器会给每个类都添加至少3个函数
//默认构造 (空实现)
//析构函数 (空实现)
//拷贝构造 (值拷贝)

class Person
{
public:
    Person()
    {
        cout << "Person 默认构造函数调用" << endl;
    }
    
    Person(int age)
    {
        m_Age = age;
        cout << "Person 有参构造函数调用" << endl;
    }

    Person(const Person & p)
    {
        m_Age = p.m_Age;
        cout << "Person 拷贝构造函数调用" << endl;
    }

    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }

    int m_Age;

};

void test01()
{
    Person p;
    p.m_Age = 18;
    
    Person p2(p);

    cout << "p2的年龄:" << p2.m_Age << endl;
}

int main()
{
    test01();

    system("pause");

    return 0;

}

运行结果:

  • Person 默认构造函数调用
  • Person 拷贝构造函数调用
  • p2的年龄:18
  • Person 析构函数调用
  • Person 析构函数调用
  • 请按任意键继续. . .

5.5.3 调用默认的拷贝构造函数

#include <iostream>
using namespace std;

//构造函数的调用规则
//1、创建一个类,C+=编译器会给每个类都添加至少3个函数
//默认构造 (空实现)
//析构函数 (空实现)
//拷贝构造 (值拷贝)

class Person
{
public:
    Person()
    {
        cout << "Person 默认构造函数调用" << endl;
    }

    Person(int age)
    {
        m_Age = age;
        cout << "Person 有参构造函数调用" << endl;
    }

    //编译器自动提高拷贝构造函数

    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }

    int m_Age;

};

void test01()
{
    Person p;
    p.m_Age = 18;

    Person p2(p);  //调用编译器默认的拷贝构造函数会把p的所有属性拷贝过来

    cout << "p2的年龄:" << p2.m_Age << endl;
}

int main()
{
    test01();

    system("pause");

    return 0;

}

运行结果:

  • Person 默认构造函数调用
  • p2的年龄:18
  • Person 析构函数调用
  • Person 析构函数调用
  • 请按任意键继续. . .

5.5.4 调用定义的有参构造函数

#include <iostream>
using namespace std;

//构造函数的调用规则
//1、创建一个类,C+=编译器会给每个类都添加至少3个函数
//默认构造 (空实现)
//析构函数 (空实现)
//拷贝构造 (值拷贝)

class Person
{
public:

    Person(int age)
    {
        m_Age = age;
        cout << "Person 有参构造函数调用" << endl;
    }

    //编译器自动提高拷贝构造函数

    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }

    int m_Age;

};


void test02()
{
    Person p; //如果写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造构造
              //由于没有默认构造函数,所以报错

    Person p2(p);
}

int main()
{
    test02();

    system("pause");

    return 0;

}

5.5.5 调用定义的拷贝构造函数

#include <iostream>
using namespace std;

//构造函数的调用规则
//1、创建一个类,C+=编译器会给每个类都添加至少3个函数
//默认构造 (空实现)
//析构函数 (空实现)
//拷贝构造 (值拷贝)

class Person
{
public:
    //如果写了拷贝构造函数,编译器就不再提供其他普通构造函数
    Person(const Person& p)
    {
        m_Age = p.m_Age;
        cout << "Person 拷贝构造函数调用" << endl;
    }

    ~Person()
    {
        cout << "Person 析构函数调用" << endl;
    }

    int m_Age;

};

void test01()
{
    Person p;    //没有默认构造函数,报错
    Person(10);  //没有有参构造函数,报错

    Person p2(p);

    cout << "p2的年龄:" << p2.m_Age << endl;
}

int main()
{
    test01();

    system("pause");

    return 0;

}

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

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

相关文章

史上最全的计算机发展编年史!!!

今天分享给大家&#xff0c;以供参考。 1614年 苏格兰人约翰纳皮尔&#xff08;John Napier&#xff09;发表了一篇论文&#xff0c;其中提到他发明了一种可以计算四则运算和方根运算的精巧装置。 1623年 威廉契克卡德&#xff08;Wilhelm Schickard&#xff09;制作了一个通过…

【从0学习Solidity】2. 值类型详解

Solidity极简入门: 2. 值类型 博主简介&#xff1a;不写代码没饭吃&#xff0c;一名全栈领域的创作者&#xff0c;专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构&#xff0c;分享一些项目实战经验以及前沿技术的见解。关注我们的主页&#xff0c;探索全栈开发…

计算机网络-谢希任第八版学习笔记总结

一.计算机网络概述 21世纪三个特点 数字化 信息化 智能化&#xff0c;其中主要是围绕智能化。 网络的常见分类&#xff1a; 电话网络 有线电视网络 计算机网络 互联网&#xff1a;Internet 由数量极大的计算机网络相连接 特点&#xff1a; 共享性 连通性 互联网&…

MySql学习笔记09——索引介绍

索引 基本概念 通过给字段名上增加索引&#xff0c;可以提高查询的效率。 一张表的一个字段可以添加一个索引&#xff0c;当然&#xff0c;多个字段联合起来也可以添加索引。索引相当于一本书的目录&#xff0c;是为了缩小扫描范围而存在的一种机制。 select * from t_user…

Java“牵手”阿里巴巴商品列表数据,关键词搜索阿里巴巴商品数据接口,阿里巴巴API申请指南

阿里巴巴商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取阿里巴巴商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问阿里巴巴商城的网页来获取商品详情信息。以下是两种常用方…

纯前端实现 导入 与 导出 Excel

最近经常在做 不规则Excel的导入&#xff0c;或者一些普通Excel的导出&#xff0c;当前以上说的都是纯前端来实现&#xff1b;下面我们来聊聊经常用到的Excel导出与导入的实现方案&#xff0c;本文实现技术栈以 Vue2 JS 为例 导入分类&#xff1a; 调用 API 完全由后端来解析数…

学习心得07:C#

之前也没有看过C#的书&#xff0c;C#的程序倒是搞了一些。好在项目不大&#xff0c;我又会套路。 C#很象是JAVA。好像就是JAVA出来之后&#xff0c;微软抄的。好东西就要学习&#xff0c;这不丢脸。 我倒是想&#xff0c;有没有办法把JAVA和C#进行映射&#xff0c;然后直接编译…

优思学院|亲和图案例:寻找六西格玛的项目

什么是亲和图&#xff1f; 亲和图&#xff08;Affinity Diagram&#xff09;主要功能在於分类归纳&#xff0c;协助在一堆杂乱无章的资料之中&#xff0c;有系统的归纳出几个大类&#xff0c;以利后续作业。通常先利用头脑风暴&#xff08;Brainstorming&#xff09;方式得到大…

WhatsApp电子商务,一个划时代的营销工具

WhatsApp电子商务就是使用WhatsApp进行在线购物&#xff0c;企业可以利用其庞大的用户群和可访问性来促进销售并提供客户服务。企业可以创建产品目录供客户浏览和进行产品查询&#xff0c;而订单可以通过WhatsApp消息或自动表格方便地下达&#xff0c;它还通过允许代理商轻松解…

【ccf-csp题解】第0次csp认证-第五题-I‘m stuck!-题解

题目描述 思路讲解 总体步骤 第一步&#xff1a;从起点正向搜索&#xff0c;能到达的地方(x,y)&#xff0c;给st1[x][y]标记为true 第二步&#xff1a;从终点反向搜索&#xff0c;能到达的地方(x,y)&#xff0c;给st2[x][y]标记为true 第三步&#xff1a;设终点位置为&…

【LeetCode】剑指 Offer <二刷>(7)

目录 题目&#xff1a;剑指 Offer 14- I. 剪绳子 - 力扣&#xff08;LeetCode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 14- II. 剪绳子 II - 力扣&#xff08;…

基于YOLOv8+PyQt5实现的共享自行车识别检测系统,含数据集+模型+精美GUI界面(可用于违规停放检测告警项目)

系列文章目录 文章目录 系列文章目录前言欢迎来到我的博客&#xff01;我很高兴能与大家分享关于基于YOLOv8的共享自行车识别检测&#xff0c;违规停放告警系统的内容。 一、系统特点7. 带有训练部分标注好的数据集&#xff0c;训练集、验证集 二、环境配置2.anaconda环境导入p…

阿里内部绝密资料——亿级并发系统架构设计(2023版)

俗话说&#xff1a;罗马不是一天建成的&#xff0c;系统的设计当然也是如此。 从原来谁都不看好的淘宝到现在的电商巨头&#xff0c;展现的不仅仅是一家互联网巨头的兴起&#xff0c;也是国内互联网行业迎来井喷式发展的历程&#xff0c;网络信号从 2G 发展到现在的 5G 通信&a…

uniapp移动端地图,点击气泡弹窗并实现精准定位

记录移动端地图map组件的使用 需求记录&#xff1a; 移动端地图部分需要展示两个定位点&#xff0c;上报点及人员定位点。通过右上角的两个按钮实现地图定位。点击对应定位气泡&#xff0c;弹出定位点的信息。 效果图如下&#xff1a; map在nvue中的使用。直接用nvue可以直接…

Python的io模块

io 模块提供了 Python 用于处理各种 I/O 类型的主要工具。三种主要的 I/O类型分别为: 文本 I/O, 二进制 I/O 和 原始 I/O。 io.open() 是内置的 open() 函数的别名. 语法&#xff1a; open(file,moder,buffering-1,encodingNone,errorsNone,newlineNone,closefdTrue,openerN…

Python基础教程:进程的调度

前言 嗨喽~大家好呀&#xff0c;这里是小曼呐 ❤ ~! 要想多个进程交替运行&#xff0c;操作系统必须对这些进程进行调度&#xff0c; 这个调度也不是随即进行的&#xff0c;而是需要遵循一定的法则&#xff0c;由此就有了进程的调度算法。 一、先来先服务调度算法 先来先服…

【IT资讯速递】清华大学推出 D-Bot,用 AI 大模型协助管理数据库;ChatGPT 与 Stack Overflow 的对决;免费在线AI工具LeiaPix:一键将图片转3D动画

2023年8月17日 星期四 癸卯年七月初二 第000004号 本文收录于IT资讯速递专栏,本专栏主要用于发布各种IT资讯&#xff0c;为大家可以省时省力的就能阅读和了解到行业的一些新资讯 IT资讯速递 一、清华大学推出 D-Bot&#xff0c;用 AI 大模型协助管理数据库二、OpenAI宣布使用G…

C语言文件读写常用函数

文章目录 1. fopen函数2. fclose函数3. fgetc函数4. fgets函数5. fputc函数6. fputs函数7. fprintf函数8. fscanf函数9. fseek函数10. ftell函数 1. fopen函数 返回值&#xff1a;文件指针&#xff08;FILE*&#xff09;参数&#xff1a;文件名&#xff08;包括文件路径&#…

用半天时间从零开始复习前端之html

目录 前言 科班生的标配&#xff1a;半天听完一门标记型语言 准备工作 webstorm2022 webstrom 第一个html页面 body h系列标签 行标签和块标签 列表标签 表格标签&#xff08;另起一篇&#xff09; 万能的input 1.快速生成多个标签 2.同时选中多个 前言 科班生的标…

算法通关村十四关:青铜-堆结构

青铜挑战-堆结构 堆结构&#xff1a;重要的基础数据结构 明确什么类型的题目可以用堆&#xff0c;以及如何用堆来解决 堆的构造和维护过程都非常复杂 1.堆的概念与特征 1.1基本概念 堆&#xff1a;是将一组数据按照 完全二叉树 的存储顺序&#xff0c;将数据存储在一个一…