能免费创建网站吗,苏州专业网站建设定制,怎样下载建设银行信用卡网站,有哪些高端的网站相关代码gitee自取#xff1a;
C语言学习日记: 加油努力 (gitee.com)
接上期#xff1a;
【C初阶】三、类和对象 #xff08;面向过程、class类、类的访问限定符和封装、类的实例化、类对象模型、this指针#xff09; -CSDN博客 引入#xff1a;类的六个默认成员函数…
相关代码gitee自取
C语言学习日记: 加油努力 (gitee.com) 接上期
【C初阶】三、类和对象 面向过程、class类、类的访问限定符和封装、类的实例化、类对象模型、this指针 -CSDN博客 引入类的六个默认成员函数 如果一个类中什么成员都没有简称为空类。但空类中并不是什么都没有任何类在什么都不写时编译器会自动生成以下六个默认成员函数默认成员函数用户没有显式实现时编译器会自动生成的成员函数称为默认成员函数 初始化和清理构造函数(1) -- 完成成员变量的初始化工作析构函数(2) -- 完成一个对象结束生命周期后的资源清理工作 拷贝复制拷贝构造函数(3) -- 使用同类对象初始化创建对象赋值重载(4) -- 把一个对象赋值给另一个对象 取地址重载主要是普通对象(5)和const对象取地址(6)这两个很少会自己实现 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 一 . 构造函数难 构造函数的概念和特性 C构造函数的概念 还是假设有以下Date类 //日期类
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;d1.Init(2023, 11, 16);d1.Print();Date d1;d1.Init(2023, 11, 17);d1.Print();return 0;
} 对于以上的Date类可以通过我们自己定义的 Init共有函数方法给对象设置日期 但如果每次创建对象时都需要调用该方法初始化对象成员的话 会有点麻烦而且可能会忘记初始化那能否在对象创建时就自动进行初始化呢 C为了优化C语言需要自己初始化的情况有了一个新概念构造函数。构造函数是特殊的成员函数其名字和类名相同创建类类型对象时由编译器自动调用进行对象的初始化 以保证每个数据成员都有一合适的初始值并且在对象整个声明周期内只会调用一次 构造函数分为有参构造函数和无参构造函数 我们在创建对象时可以设置各成员变量初始化的值 如果没有设置则对象初始化时会调用无参构造函数 如果设置了则对象初始化时会调用相应的有参构造函数 Date类 -- 图示 主函数通过构造函数创建对象 -- 图示 --------------------------------------------------------------------------------------------- C构造函数特征 构造函数名和类名相同构造函数没有返回值对象实例化时编译器会自动调用对应的构造函数 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义构造函数编译器将不再自动生成构造函数所以如果定义了有参构造函数最好再定义一个无参构造函数防止创建对象时需要无参构造函数而又无法调用到 构造函数也是函数可以有参数所以也可以对其设置缺省参数将一个有参构造函数初始化全部成员变量的构造函数的所有参数都设置一个缺省参数全缺省构造函数这样该构造函数就既实现了有参构造函数的任务又实现了无参构造函数的任务因为初始化对象时如果不给初始化值 那么有参构造函数的缺省参数就会发挥作用实现无参构造函数的任务这样一个构造函数就可以替代有参和无参两个构造函数了 构造函数支持重载虽然支持重载但如果已经定义了全缺省构造函数已经能够实现无参构造函数的情况下这时如果再定义一个无参构造函数虽然构成了构造函数重载 但是实际调用时是会出错的因为全缺省构造函数和无参构造函数的功能重复了编译器就会不知道该调用哪个构造函数了 无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个否则会有调用歧义注意无参构造函数、全缺省构造函数、编译器默认生成的构造函数都可以认为是默认构造函数 不传参数还可以被调用的构造函数都可以叫默认构造函数 全缺省构造函数 -- 图示 编译器默认生成的构造函数的作用 C中把类型分成了内置类型基本类型和自定义类型内置类型就是语言原生的数据类型int、double、指针……自定义类型就是我们使用 class / struct / union 自己定义的类型。关于编译器生成的默认构造函数该构造函数会对我们未定义的成员变量进行初始化 不同编译器的初始化方式不同VS2013中 如果对象的成员变量为内置类型默认生成构造函数不会对其进行处理为随机值 如果对象的成员变量为自定义类型默认生成构造函数则会调用该自定义类型的默认构造函数VS2019中情况会更复杂如果对象的成员变量全是内置类型默认生成构造函数不会对其进行处理为随机值 如果对象的成员变量既有内置类型又有自定义类型 则会对其中的内置类型进行处理int类型成员变量会被初始化为0对其中的自定义类型会调用该自定义类型的默认构造函数 所以默认生成的构造函数会根据对象的成员变量的情况来判断是否要对其进行处理 如果对象的成员变量为自定义类型就调用该自定义类型的默认构造函数如果是内置类型则不进行处理为随机值 会处理自定义类型不一定处理内置类型(看编译器)建议统一当成不会进行处理 图示 因此C11中针对内置类型成员不初始化的缺陷又打了一个补丁内置类型成员变量在类中声明时可以给默认值 给了默认值又有定义显式构造函数的话以显式构造函数为准 图示 总结 一般情况下我们都要自己写构造函数 成员变量如果都是自定义类型或者成员变量声明时给了缺省值 那就可以考虑让编译器自己生成构造函数 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 二 . 析构函数 析构函数的概念和特性 C析构函数的概念 通过前面对构造函数的了解我们知道了一个对象是怎么来的可一个对象又是怎么没的呢如果说构造函数是我们以前写的Init初始化函数 那么析构函数就是我们以前写的Destroy“销毁”函数 析构函数和构造函数的功能相反但析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。 而对象在销毁时会自动调用析构函数完成对象中资源的清理工作 --------------------------------------------------------------------------------------------- C析构函数的特性 析构函数名 在类名前加上字符 “~” 按位取反符号 析构函数没有返回值和函数参数 一个类只能有一个析构函数若没有显式定义编译器会自动生成默认的析构函数 注析构函数不支持重载 对象声明周期结束时C编译系统会自动调用析构函数 析构函数 -- 图示 编译器默认生成的构造函数的作用 默认生成的析构函数其行为跟构造函数的类似针对内置类型的成员变量析构函数不会对其进行处理针对自定义类型的成员变量析构函数也会调用该自定义类型的默认析构函数 如果类中没有申请资源析构函数可以不写直接使用编译器生成的默认析构函数比如之前写的Date日期类就可以不写而如果类中有申请资源则一定要写析构函数否则会导致资源内存泄漏比如Stack栈类就需要显式定义析构函数进行资源清理 图示 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 三 . 拷贝构造函数难 拷贝构造函数的概念和特性 C拷贝构造函数的概念 拷贝构造函数只有单个形参该形参是对本类类型对象的引用一般常用const修饰在使用已存在的类类型对象拷贝创建新对象时由编译器自动调用 图示 --------------------------------------------------------------------------------------------- C拷贝构造函数的特性 拷贝构造函数也是特殊的成员函数是构造函数的一个重载形式 拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式作为其参数编译器会直接崩溃因为会引发无穷递归调用 如果没有显式定义拷贝构造函数编译器会生成默认的拷贝构造函数。默认的拷贝构造函数拷贝对象时会按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝 注 在编译器生成的默认拷贝构造函数中内置类型是按照字节方式直接拷贝的值拷贝 而自定义类型则会调用该自定义类型的拷贝构造函数完成拷贝 图示 编译器生成的默认拷贝构造函数已经可以完成字节序的值的拷贝值拷贝了当类中没有涉及资源申请申请动态空间等时浅拷贝已经足够使用了是否显式定义拷贝构造函数都可以 但是一旦涉及到了资源申请时则拷贝构造函数是一定要显式定义的进行深拷贝 图示 拷贝构造函数典型调用场景使用已存在的对象来“拷贝”创建新对象、函数参数类型为类类型对象、函数返回值类型为类类型对象 注 为了提高效率一般对象传参时尽量使用引用类型返回返回时根据实际场景能用引用返回尽量使用引用返回 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 四 . 赋值运算符重载 运算符重载的使用和注意事项 引言 对于内置类型int、double……的数据我们可以直接对其使用运算符假设我们有整型变量a和b我们可以对其使用a b判断相等 、a b判断大小但对自定义类型的数据而言就不能直接对其使用运算符 因为编译器不知道怎么判断我们自定义的类型所以需要我们自己定义其判断的规则 图示 -- 自定义类型判断规则 --------------------------------------------------------------------------------------------- 运算符重载的使用 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其返回值类型、函数名字以及参数列表其返回值类型与参数列表和普通的函数类似 函数名字关键字operator后接需要重载的运算符符号 如加法运算符重载 -- operator 函数原型返回值类型 operator操作符(参数列表) 图示 -- 类外运算符重载 --------------------------------------------------------------------------------------------- 运算符重载的注意事项 不能通过连接其它符号来创建新的操作符比如operator 重载操作符必须有一个类类型参数 用于内置类型的运算符其含义不能改变例如内置的整型 不能改变其含义 和 是不一样的 重点作为类成员函数重载时其形参看起来比操作数数目少一个因为成员函数的第一个参数为隐藏的this指针 注意以下五个运算符不能重载 “ .* ” 、“ :: ” 、“ sizeof ” 、“ ?: ” 、“ . ” 图示 -- 类中运算符重载 一个类要重载哪些运算符主要看这个运算符对这个类来说有没有意义有意义就可以重载没有意义就不要重载对日期类来说日期的 (加) *(乘) /(除) 都没有意义但 -(减) 是有意义的两个日期相减可以计算两日期相差了多少天日期日期没有意义但日期整型是有意义的如d1 100 计算d1日期的100天后的日期 图示 -- 类中实现 和 运算符重载 注“”运算符重载中要设置返回值 -- return *this 这里忘了写了 赋值运算符重载 赋值运算符 -- 赋值运算符重载就是让自定义类型也能像内置类型一样使用”“ 赋值运算符重载格式 参数类型const Tconst修饰参数能够防止赋值拷贝时左右值写反了导致改变了原对象T 传参引用接收右值的“别名”提高传参效率 返回值类型T引用返回可以提高返回的效率设置返回值还为了支持“”的连续赋值 定义赋值运算符重载函数时需要检测是不是“自己给自己赋值”的情况 最终返回*this即返回被赋值对象本身能够符合“”连续赋值的含义 用户没有显式实现时编译器会生成一个默认的赋值运算符重载函数其行为和拷贝构造函数类似针对内置类型成员变量进行 值拷贝浅拷贝针对自定义类型成员变量会调用该自定义类型的 赋值运算符重载函数注意 如果类中没有“资源”Date类赋值运算符重载函数要不要显式定义都可以如果类中有“资源”Stack类赋值运算符重载函数必须要显式定义 赋值运算符只能重载成类的成员函数只能在类中定义重载不能重载为全局函数原因赋值运算符重载函数如果不显式实现编译器会生成一个默认的。此时如果再在类外实现一个全局的赋值运算符重载函数就会和编译器在类中生成的默认赋值运算符重载函数冲突了所以赋值运算符重载函数只能是类的成员函数 图示 -- 以Date类为例