6.C++面向对象2(默认成员函数,构造函数,析构函数详解)

embedded/2024/9/25 6:16:20/

⭐本篇为C++学习第6章,主要了解默认成员函数,构造函数析构函数

⭐本人Gitee C++代码仓库:yzc的c++学习: 小川c++的学习记录 - Gitee.com 

目录

一. 类的6个默认成员函数

二. 构造函数

三.析构函数

 四 多个对象调用构造函数析构函数的顺序

五. 下章重点

5.1 拷贝构造函数

5.2 运算符重载和赋值运算符重载


一. 类的6个默认成员函数

        对于一个空类来说,其大小是1,但是空类中真的什么都没有吗??

其实,任何类在什么都不写时候,编译器会默认生成6个成员函数

1. 完成类对象的初始化和清理工作:

        构造函数用于完成对象的初始化

        析构函数用于完成对象的清理

2. 完成类对象的拷贝和赋值:

        拷贝构造用于完成类初始化时候使用一个对象拷贝另一个对象

        赋值运算符重载用于使用一个对象赋值给另一个对象

3. 取地址重载:

        普通对象和const对象的取地址重载,我们很少自己实现

注意:

1. 默认生成的构造函数析构函数。针对成员变量:内置类型不会处理,但是成员变量是其他类的话,会调用这个类的构造函数

2.默认生成的拷贝构造和赋值运算符重载。只会按字节序拷贝(浅拷贝)

也就是说,很多类不需要我们去实现这些函数,编译器会自动生成。

但是对于拷贝构造和赋值运算符重载。由于C++默认生成的是浅拷贝,这会造成错误。如:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;class A
{
public:A(int a = 0){_a = &a;}~A(){free(_a);}
private:int* _a;
};int main()
{A a;A b(a);A c(2);a = c;return 0;
}

由于默认的浅拷贝,对象a,b,c中的_a指向同一块空间。

当调用析构函数的时候,这块空间会被析构多次,就会报错。

所以,我们需要自己实现拷贝函数和赋值运算符重载的深拷贝,以避免出现这种问题。

二. 构造函数

        我们以时间类为例,逐步讲解。

我们知道,在C语言可以在结构体中实现一个Init函数,用于初始化结构体

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;class Time
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){cout << _year << "/" << _month << "/" << _day;}
private:int _year;int _month;int _day;
};int main()
{Time t1;t1.Init(2024, 9, 24);//完成初始化工作t1.print();return 0;
}

但是这种方法有点麻烦,我们能不能在创建对象的时候就初始化呢?

这个时候就需要使用构造函数来完成这个功能

构造函数的名称和类名是一样的!

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;class Date
{
public://无参的构造函数Date(){_year = 0;_month = 0;_day = 0;}//有参的构造函数Date(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 t1;Date t2(2024, 9, 24);t1.print();t2.print();return 0;
}

运行结果: 

使用构造函数,我们能够方便地对对象进行初始化

对于有参和无参构造函数,我们还能使用缺省值的特点来合并。

	//带缺省值的构造函数,合并了有参构造和无参构造Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}

注:

1. 构造函数(在对象初始化调用的函数) ---> 完成类的初始化工作,

a 函数名和类名相同,无返回值

b 对象初始化的时候自动调用类中的构造函数

c 构造函数可以重载,完成不同对象的初始化(有参和无参)

d 如果类中没有自定义构造函数,编译器会默认生成一个无参的构造函数

e 如果用户自定义了一个有参的构造函数,那么系统不会自动生成,这个时候需要用户自己定义一个无参的默认构造函数

默认构造函数针对内置类型成员变量没有初始化,针对自定义类成员变量,会调用其的构造函数进行初始化,如:

class A
{
public:A(int a = 0){_a = a;}private:int _a;
};class B
{int _b;A a;
};

B的默认构造函数会调用A的相应构造函数

在实际应用中,我们更倾向于使用全缺省的默认构造函数

f 无参的构造函数和全缺省的构造函数统称为默认构造函数,但是默认构造函数只能存在一个,所以这两个函数只能定义一个,两个同时存在会造成歧义

三.析构函数

        析构函数用于完成对象的清理工作。当对象的生命周期结束后,就会自动调用。

class Date
{
public://带缺省值的构造函数,合并了有参构造和无参构造Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}//析构函数,由于没有使用new,malloc等开辟空间。函数内部为空~Date(){}void print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};

注:

析构函数(用于完成对象的清理工作)

a 析构函数无返回值,无参数。

b 析构函数名字的在类名前加~

c 一个类只有一个析构函数,若用户没有自定义,编译器会默认生成一个

d 当对象的生命周期结束后,会自动调用其析构函数

e 和构造函数类似,默认生成的构造函数不会处理内置类型,对于类成员变量,会调用该类的析构函数

f 析构函数完成的是对象的清理,不是对象的销毁

g 注意析构的顺序,后创建的对象先析构

 四 多个对象调用构造函数析构函数的顺序

#include<iostream>
using namespace std;class A
{
public:A(){cout << "调用A构造函数A()" << endl;}~A(){cout << "调用A析构函数~A()" << endl;}
};class B
{
public:B(){cout << "调用B构造函数B()" << endl;}~B(){cout << "调用B析构函数~B()" << endl;}A a;
};int main()
{A a1;B b1;A a2;B b2;return 0;
}

分析一下,上面的的代码输出是什么??

应该是:

调用A构造函数A()        //a1

调用A构造函数A()        //b1

调用B构造函数B()        //b1

调用A构造函数A()        //a2

调用A构造函数A()        //b2

调用B构造函数B()        //b2

调用B析构函数~B()        //b2(后创建,先析构)        

调用A析构函数~A()        //b2

调用A析构函数~A()        //a2

调用B析构函数~B()        //b1

调用A析构函数~A()        //b1

调用A析构函数~A()        //a1

运行结果如下

 

五. 下章重点

5.1 拷贝构造函数

5.2 运算符重载和赋值运算符重载


http://www.ppmy.cn/embedded/116484.html

相关文章

ubuntu挂载磁盘或U盘

方法 在Ubuntu中&#xff0c;使用命令行读取U盘通常涉及到以下几个步骤&#xff1a;插入U盘、查找设备名称、挂载U盘以及访问文件。以下是详细步骤&#xff1a; 1. 插入U盘 将U盘插入计算机的USB端口。 2. 查找设备名称 你可以使用lsblk或dmesg命令来查找新插入的U盘设备名…

游戏开发2025年最新版——八股文面试题(unity,虚幻,cocos都适用)

1.静态合批与动态合批的原理是什么&#xff1f;有什么限制条件&#xff1f;为什么&#xff1f;对CPU和GPU产生的影响分别是什么&#xff1f; 原理&#xff1a;Unity运行时可以将一些物体进行合并&#xff0c;从而用一个描绘调用来渲染他们&#xff0c;就是一个drawcall批次。 限…

Linux 基本指令的学习

01. ls 指令 语法 &#xff1a; ls [ 选项 ][ 目录或文件 ] 功能 &#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含…

从 Oracle 集群到单节点环境(详细记录一次数据迁移过程)之一:生产环境与目标服务器详情

从 Oracle 集群到单节点环境&#xff08;详细记录一次数据迁移过程&#xff09;之一&#xff1a;生产环境与目标服务器详情 目录 从 Oracle 集群到单节点环境&#xff08;详细记录一次数据迁移过程&#xff09;之一&#xff1a;生产环境与目标服务器详情一、操作系统环境二、Or…

springboot整合openfeign

文章目录 准备一、引入必要依赖二、写一个feign client并暴露到注册中心2.1 client2.2 开启Feign客户端功能 三、别的服务引入IProductClient并调用方法3.1 建一个order-service&#xff0c;引入IProductClient所在模块3.2 注入IProductClient&#xff0c;并调用方法 四、启动服…

【计算机网络 - 基础问题】每日 3 题(二十)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

01_WebRtc_一对一视频通话

文章目录 通话网页的设计客户端实现Web的API 服务端实现 2024-9-20 很久没有写博客啦&#xff0c;回顾总结这段时间的成果&#xff0c; 写下博客放松下&#xff08;开始偷懒啦&#xff09;主要内容&#xff1a;实现网页&#xff08;html&#xff09;打开摄像头并显示到页面需要…

线程池和JUC

1. 线程池 1.1 线程状态介绍 当线程被创建并启动以后&#xff0c;它既不是一启动就进入了执行状态&#xff0c;也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢&#xff1f;Java中的线程 状态被定义在了java.lang.Thread.Stat…