【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

在这里插入图片描述

C++入门

  • 六个默认成员函数
  • 1 构造函数
    • 语法
    • 特性
  • 2 析构函数
    • 语法
    • 特性
  • 3 拷贝构造函数
    • 特性
  • 4 赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 特例:前置++ 与 后置++
      • 前置++:返回+1之后的结果
      • 后置++:
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

六个默认成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗? 并不是
任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数
我们实现了,编译器就不会生成了
在这里插入图片描述

1 构造函数

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

语法

  1. 函数名与类名相同。
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载(最好实现一个全缺省的构造函数)
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}void show() {cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);//默认构造Date yesterday(2024, 2, 17);//默认构造today.show();yesterday.show();return 0;
}

来看效果在这里插入图片描述

特性

  1. 如果类中没有显示定义构造函数,C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不在生成。

  2. 关于编译器生成的默认成员函数,有个疑惑:不实现构造函数的情况下,编译器会生成 默认的构造函数。但是看起来默认构造函数又没什么用?Date对象调用了编译器生成的默认构造函数,但是Date对象_year / _month / _day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员 _t 调用的它的默认成员函数。

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

上面程序会对 _t 进行默认构造,由于我们编写了构造函数,_t 中 的内容成功初始化,但是_year / _month / _day缺依然是随机值。

  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数

2 析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

语法

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
    下面的栈可以帮助我们理解析构函数的作用
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 析构函数~Stack(){	//如果 不为空if (_array){   // 释放指针free(_array);//初始化_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);//生命周期结束自动析构清理
}

特性

关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

调用自定义类型 time 的析构函数
在这里插入图片描述
注意 :
析构函数的调用顺序,先创建先销毁,先销毁局部变量,在销毁全局变量。
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类

3 拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用

特性

  1. 拷贝构造是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用直接的传值编译器会直接报错,因为会引发无穷递归调用。
    原因:传值拷贝时
    第一步:开辟一个临时空间;
    第二步:由于临时空间是需要构造的,重新调用拷贝构造函数(无穷递归形成…)

在这里插入图片描述

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
  2. 浅拷贝不能实现复杂的类拷贝,涉及指针等内容会拷贝失败。
  3. 拷贝构造函数典型调用场景:
    使用已存在对象创建新对象
    函数参数类型为类类型对象
    函数返回值类型为类类型对象

4 赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator"操作符" (参数列表)

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  4. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

来看样例:

class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date yesterday(2024, 2, 17);today.show();yesterday.show();cout << "operator==()\n" << (today == yesterday) << endl;return 0;
}

在这里插入图片描述不相等返回假。

赋值运算符重载

  1. 赋值运算符重载格式
    参数类型:const T&,传递引用可以提高传参效率
    返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
    检测是否自己给自己赋值
    返回*this :要复合连续赋值的含义
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}//运算符重载bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}//赋值运算符重载Date& operator=(const Date& d){if(this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date day = today;today.show();day.show();return 0;
}

在这里插入图片描述
可以成功赋值。

  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数
    原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数
  2. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了
还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType *_array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1;return 0;
} 

这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现

特例:前置++ 与 后置++

前置++:返回+1之后的结果


// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
{_day += 1;return *this;
}

后置++:

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
注意:
后置++是 先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1,


Date operator++(int)
{Date temp(*this);_day += 1;// temp是临时对象,因此只能以值的方式返回,不能返回引用return temp;
}

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

电视盒子什么牌子好?老烧实测2024电视盒子排行榜

电视盒子价格不贵&#xff0c;但功能丰富&#xff0c;看点播、直播&#xff0c;玩游戏&#xff0c;上网课等都不在话下&#xff0c;对大部分家庭来说电视盒子是必备的。不过面对众多产品的时候我们都不知道电视盒子什么牌子好&#xff0c;我是多年电视盒子老用户了&#xff0c;…

ARM 之十六 详解 CMSIS 版本变迁、各组件使用示例

目前,CMSIS 已经发展到了第六版,其目录结构也发生了重大的变化。在不断发展中,很多原来 CMSIS 的组件被不断独立出去,并因此成立了很多开源社区,今天就来学习一下! 由于 CMSIS 已经包含了相当丰富的文档,因此,本文重点学习版本之间的变化以及一些实际使用示例。 什么是…

常见设计模式详细版

文章目录 单例模式饿汉式单例模式懒汉式单例模式双重检索单例模式 工厂模式简单工厂模式工厂&#xff08;方法&#xff09;模式抽象工厂模式 原型模式代理模式 单例模式 确保一个类只有一个实例&#xff0c;并且自行实例化并向整个系统提供这个实例。 饿汉式单例模式 饿汉式单…

统计图柱形图绘制方法

统计图柱形图绘制方法 常用的统计图有条形图、柱形图、折线图、曲线图、饼图、环形图、扇形图。 前几类图比较容易绘制&#xff0c;饼图环形图绘制较难。 今提供条形图和柱形图的绘制方法&#xff0c;附加环形图和艺术环图的绘制方法供参考。 本方法采用C语言的最基本功能&…

力扣51. N 皇后(回溯)

Problem: 51. N 皇后 文章目录 题目描述思路解决方法复杂度Code 题目描述 思路 1.决策路径&#xff1a;board中小于row的那些行都已经成功放置了皇后&#xff1b; 2.选择列表&#xff1a;第row行的所有列都是放置皇后的选择&#xff08;则根据N皇后相互攻击的股则编写判断当前决…

2024几个测试接口的好工具,效率加倍~

作为一名后端程序员&#xff0c;一定要对自己写的接口负责&#xff0c;保证接口的正确和稳定性。因此&#xff0c;接口测试也是后端开发中的关键环节。 但我相信&#xff0c;很多朋友是懒得测试接口的&#xff0c;觉得这很麻烦。一般自己写的接口自己都不调用&#xff0c;而是…

探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;并且坚持默默的做事。 引言&#xff1a;探索命令模式的奥秘 软件设计领域充满挑战与机遇&#xff0c;命令模式…

Jlink+OpenOCD+STM32 Vscode 下载和调试环境搭建

对于 Mingw 的安装比较困难&#xff0c;国内的网无法正常在线下载组件&#xff0c; 需要手动下载 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z 版本的软件包&#xff0c;添加环境变量&#xff0c;并将 mingw32-make.exe 名字改成 make.exe。 对于 OpenOCD&#xff0c;需要…

TrueNAS-SCALE安装步骤及基本设置(存储池、数据集、用户,权限,SMB 共享等)

目录 基本配置安装前准备安装关于TrueNASNAS是什么TrueNAS是什么为什么选择TrueNAS 服务器基本设置更改语言创建存储池创建数据集设置用户和用户组设置SMB共享数据集权限设置 基本设置中的概念存储池和数据集SMB 共享 映射网路驱动器其他注意事项总结 基本配置 操作系统版本Tr…

Spring Boot java -jar --spring.profiles.active=dev 失效问题

之前动态部署修改配置文件的情况不多&#xff0c;所以也没注意过&#xff0c;这个问题今天困扰了好久&#xff0c;经过多方查询后得到了解决办法 直接上代码 <profiles><profile><!-- 本地开发环境 --><id>dev</id><properties><profi…

外汇天眼:前高盛分析师因内幕交易和欺诈罪被判刑22个月

在南华克皇冠法院进行的判决听证会后&#xff0c;35岁的穆罕默德齐纳&#xff08;Mohammed Zina&#xff09;今天因内幕交易和欺诈罪被判刑22个月。 穆罕默德齐纳于2024年2月15日在南华克皇冠法院经过为期12周的审判后&#xff0c;因六项内幕交易罪和三项欺诈罪被裁定有罪&…

《白话C++》第10章 STL和boost,Page74 10.4.4 std::unique_ptr

std::unique_ptr可以同时处理普通指针和指向数组的指针&#xff1a; unique_ptr像是auto_ptr的功能改良版 第一个改进就是可以管理指向单一对象的指针&#xff0c;也可以管理指向连续对象&#xff08;数组&#xff09;的指针。 第二个&#xff0c;unique_ptr改进的是&#xf…