C++从零到满绩——类和对象(中)

news/2024/11/25 10:12:28/

 

目录

1>>前言

2>>构造函数(我称之为初始化函数)

3>>析构函数(我称之为销毁函数)

4>>拷贝构造函数(我称之为复制函数)

 5>>运算符重载

5.2>>赋值运算符重载

​编辑

6>>结语

1>>前言

        上节课学习了基础篇(包括函数重载、引用、inline、nullptr)and类和对象(上)(包括类的定义、实例化、this指针),忘记的宝子们可以去复习一下~~~

枫の大一-CSDN博客C++从零到满绩——入门基础and类和对象(上)-CSDN博客  跳转上篇

枫の大一-CSDN博客  跳转个人主页查看

        今天我们来类和对象(中)(包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载)。需要注意的是今天我们学习的四个内容 始终 带着两个疑问:

第一:我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求?

第二:编译器默认生成的函数不满足我们的需求,我们需要自己实现,那么如何自己实现?

ps:如果有觉得小编哪里需要改进的欢迎指出,做出完美的C++篇章肯定少不了各位精神股东的支持啦,谢谢大家~

2>>构造函数(我称之为初始化函数)

        构造函数虽然有构造二字,但它并非开空间造对象,而是在对象实例化时初始化对象。它的本质就是替代之前写的init初始化函数,并且它还能自动调用,简直perfect!

构造函数的特点:

1.函数名域类名一样。

2.无返回值。没有void!!!

3.对象实例化时会自动调用。

4.构造函数可重载。

5.如果类中没有显式定义(我们自己写的)构造函数,编译器会自动生成无参默认构造函数。

6.默认构造包括:无参构造函数、全缺省构造函数、编译器默认生成的构造函数。简单说就是不需要我们传实参就是默认构造。

7.编译器默认生成的构造函数,对于内置类型初始化不确定,看编译器;对于自定义类型成员变量,要求调用这个成员变量的默认构造函数进行初始化。类似于高数的链式求导,y不能对x求导,可以对t求导,t在对x求导。

#include<iostream>
using namespace std;
class Date {
public://公共void print() {//打印函数cout << _year << "/" << _month << "/" << _day << endl;}
private://私有int _year;int _month;int _day;
};
int main() {Date d1;d1.print();return 0;
}

 不写构造函数运行结果为随机值

#include<iostream>
using namespace std;
class Date {
public://公共Date(int year = 1, int month = 1, int day = 1) {//构造函数_year = year;_month = month;_day = day;}void print() {//打印函数cout << _year << "/" << _month << "/" << _day << endl;}
private://私有int _year;int _month;int _day;
};
int main() {Date d1(2024, 11, 24);d1.print();return 0;
}

写了构造函数对变量d1进行了初始化操作,还用到了上节课的缺省参数 

 

d1这里后面什么都不写

Date d1;

运行结果为1/1/1,因为缺省参数帮助初始化了。 

 

可以发现我们没有进行调用,而是在实质化对象的时候自动调用,这就是它的好用之处。这就是构造函数的使用。

3>>析构函数(我称之为销毁函数)

        析构函数功能与构造函数相反,听名字可以理解为解析构造,将构造函数一步步剖析。它的工作是完成对象中资源的清理释放工作。类似与之前栈使用的Destroy功能。

析构函数的特点:

1.析构函数名是在类名前加上字符~。~本身也是按位取反的意思,这里代表相反。

2.无参数无返回值。不需要void!!!

3.一个类只能有一个析构函数。

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

5. 自定义类型的成员变量都会调用析构函数(不管是写的还是默认生成的)。

6.若类无申请资源,析构可以不写,如Date;若类都是自定义成员变量,它们都有自己的析构,也可以不写,如用两个栈实现队列的MyQueue;若有申请资源,一定要写,如用两个栈实现队列的Stack。

7.若有多个对象,后定义的先析构。

#include<iostream>
using namespace std;
typedef int StDataType;
class Stack {
public://公共Stack(int n=4) {//构造函数_arr = (StDataType*)malloc(sizeof(StDataType) * n);if (nullptr == _arr){perror("malloc获取失败");return;}_capacity = n;_top = 0;}~Stack() {//析构函数free(_arr);_arr = nullptr;_capacity = _top = 0;}
private://私有StDataType* _arr;int _capacity;int _top;
};
int main() {Stack st;return 0;
}

4>>拷贝构造函数(我称之为复制函数)

        拷贝构造函数第一个参数时自身类型的引用,其他参数都是缺省参数。

拷贝构造的特点:

1.拷贝构造函数是构造函数的重载。

2.拷贝构造参数第一个必须是自身类型的引用。

3.自定义类型对象进行拷贝时必须调用拷贝构造,因此传值传参和传值返回的行为都会调用拷贝构造。

4.若未自己写,编译器会自动生成。自动生成的拷贝构造是值拷贝/浅拷贝(一个字节一个字节拷贝),自定义成员变量会调用它的拷贝构造。

5.需要我们写析构的也要写拷贝构造,例如Stack。因为它有申请资源,浅拷贝会导致两块st1和st2都指向同一块空间,因此要进行深拷贝,所以要自己写。

6.传值返回会调用拷贝构造,传值“引用”返回没产生拷贝,因此不需要调用。但是如果返回的引用时一个局部对象,在函数结束时销毁,那么引用会变成野引用,那就不行。传引用返回前提是函数结束后还在。

#include<iostream>
using namespace std;
class Date {
public://公共Date(int year = 1, int month = 1, int day = 1) {//构造函数_year = year;_month = month;_day = day;}void print() {//打印函数cout << _year << "/" << _month << "/" << _day << endl;}
private://私有int _year;int _month;int _day;
};
int main() {Date d1(2024,11,24);Date d2(d1);d1.print();d2.print();return 0;
}

 

 用栈的拷贝构造:

//拷贝构造
#include<iostream>
using namespace std;
typedef int StDataType;
class Stack {
public://公共Stack(int n = 4) {//构造函数_arr = (StDataType*)malloc(sizeof(StDataType) * n);if (nullptr == _arr){perror("malloc获取失败");return;}_capacity = n;_top = 0;}Stack(const Stack& source) {//拷贝构造函数//需要再开辟一个同样大小空间_arr = (StDataType*)malloc(sizeof(StDataType) * source._capacity);//乘上之前空间大小if (nullptr == _arr){perror("malloc获取失败");return;}memcpy(_arr, source._arr, sizeof(StDataType) * source._top);//复制有效数据_capacity = source._capacity;_top = source._top;}~Stack() {//析构函数free(_arr);_arr = nullptr;_capacity = _top = 0;}
private://私有StDataType* _arr;int _capacity;int _top;
};
int main() {Stack st;Stack st2(st);return 0;
}

 5>>运算符重载

1.这里重载和之前的函数重载区分开,并不是一个意思。

2.当两个类类型对象进行运算符操作时,不能直接操作,需要我们写一个对应的运算符重载函数才可以。

3.它由operator和定义的运算符构成。

4.它的参数个数和运算对象一样多。

5.如果一个重载运算符函数是成员函数,那它少一个参数,因为有隐藏的this指针。

6.特别注意5个运算符不能重载:(.*  ::  sizeof  :?  .)

7.至少有一个类类型参数。

//运算符重载
#include<iostream>
using namespace std;
class Date {
public://公共Date(int year = 1, int month = 1, int day = 1) {//构造函数_year = year;_month = month;_day = day;}bool operator==(const Date& d2) {//重载格式:operator符号return _year == d2._year&& _month == d2._month&& _day == d2._day;}void print() {//打印函数cout << _year << "/" << _month << "/" << _day << endl;}
private://私有int _year;int _month;int _day;
};
int main() {Date d1(2024,11,24);Date d2(d1);int r= d1 == d2;cout << r;return 0;
}

5.2>>赋值运算符重载

        跟拷贝构造区分开,它是两个已经存在的对象进行赋值。

赋值运算符重载特点:

1.必须重载为成员函数,建议带上const。

2.有返回值,写当前类类型的引用,提高效率。

 

//赋值运算符重载
#include<iostream>
using namespace std;
class Date {
public://公共Date(int year = 1, int month = 1, int day = 1) {//构造函数_year = year;_month = month;_day = day;}Date& operator=(const Date& d2) {//重载格式:operator符号//跳过自己给自己赋值if (this != &d2) {_year = d2._year;_month = d2._month;_day = d2._day;}//因为d1=d2返回的是d1,而*this也是d1,所以返回*thisreturn *this;}void print() {//打印函数cout << _year << "/" << _month << "/" << _day << endl;}
private://私有int _year;int _month;int _day;
};
int main() {Date d1(2024, 11, 24);Date d2(2024, 11, 299);d1 = d2;d1.print();d2.print();return 0;
}

6>>结语

        今日份C++入门就先到这里啦,来总结一下:主要讲了类和对象(中)(包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载),感兴趣的宝子们欢迎持续订阅小编,小编在这里谢谢宝子们啦~C++的学习很陡,时而巨难时而巨简单,希望宝子和小编一起坚持下去~你们的三连是我的动力,感谢支持~


http://www.ppmy.cn/news/1549790.html

相关文章

低温存储开关机问题

问题&#xff1a; 某消费电子产品在进行可靠性实验室&#xff0c;在低温-30C存储两个小时后&#xff0c;上电不开机。在常温25C时&#xff0c;开关机正常。 分析&#xff1a; 1、接串口抓log信息&#xff0c;从打印信息可以看出uboot可以起来&#xff0c;在跑kernel时&#x…

React Native 基础

React 的核心概念 定义函数式组件 import组件 要定义一个Cat组件,第一步要使用 import 语句来引入React以及React Native的 Text 组件: import React from react; import { Text } from react-native; 定义函数作为组件 const CatApp = () => {}; 渲染Text组件

aws服务(二)机密数据存储

在AWS&#xff08;Amazon Web Services&#xff09;中存储机密数据时&#xff0c;安全性和合规性是最重要的考虑因素。AWS 提供了多个服务和工具&#xff0c;帮助用户确保数据的安全性、机密性以及合规性。以下是一些推荐的存储机密数据的AWS服务和最佳实践&#xff1a; 一、A…

力扣 LeetCode 404. 左叶子之和(Day8:二叉树)

解题思路&#xff1a; 后序遍历 左叶子节点&#xff1a;父节点的左节点不为空&#xff0c;该左节点的左右节点都为空 class Solution {public int sumOfLeftLeaves(TreeNode root) {return recur(root);}public int recur(TreeNode root) {if (root null) return 0;if (roo…

R虚拟环境中安装ncdf4库包编译库问题

目录 R虚拟环境中安装ncdf4的问题 解决方案 R虚拟环境中安装ncdf4的问题 > install.packages("ncdf4")trying URL https://mirrors.bfsu.edu.cn/CRAN/src/contrib/ncdf4_1.23.tar.gzContent type application/octet-stream length 125897 bytes (122 KB)downloa…

统计学习方法中的模型评估与模型选择

一、训练误差与测试误差 1、预测 统计学习的目的是使学到的模型不仅对已知数据而且对未知数据都能有很好的预测能力。 不同的学习方法会给出不同的模型。 当损失函数给定时&#xff0c; 基于损失函数的模型的训练误差(training error)和模型的测试误差(test error)就是学习方…

TCP(Transmission Control Protocol,传输控制协议)报文段的首部格式

---------------------------------------------------------------- | 源端口 | 目的端口 | 序号 | 确认号 | | 2字节 | 2字节 | 4字节 | 4字节 | ---------------------------------------------------…

2024年亚太地区数学建模大赛C题-宠物行业及相关行业的发展分析与策略

随着人们消费理念的发展&#xff0c;宠物产业这一新兴产业&#xff0c;由于经济的快速发展和人均收入的不断增长&#xff0c;在全球范围内逐渐发展起来。1992年&#xff0c;中国小动物保护协会成立&#xff0c;1993年&#xff0c;皇家犬犬和火星等国际宠物品牌进入中国市场。随…