类的默认成员函数(C++)

您所在的位置:网站首页 获取数据成员的函数有哪些 类的默认成员函数(C++)

类的默认成员函数(C++)

2024-07-08 03:40:56| 来源: 网络整理| 查看: 265

类的默认成员函数 类的6个默认成员函数构造函数析构函数拷贝构造运算符重载const 修饰类的成员变量取地址及const取地址操作符重载默认函数实现日期类

之前我们看到,一个空类他其实也是有大小的,但是我们所定义的空类就真的什么也没有,只是一个空类吗?

类的6个默认成员函数

总的来说,任何一个类在我们什么都不写的情况下,都会自动生成6个默认的成员函数。

构造函数:完成初始化工作析构函数:完成清理函数拷贝构造:使用同一个类的对象初始化创建对象赋值重载:主要是把一个对象赋值给另一个对象取地址重载:有两个函数,主要是对普通对象和const对象取地址

但是这些默认生成的成员函数也不一定是靠谱的。 在这里插入图片描述

构造函数 class Data { public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };

这样的类,我们每次在创建一个新的对象的时候都需要完成初始化的操作,而在C++中对这一个过程做了优化,允许在创建类的时候对类中的成员变量进行初始化,看上去很神奇,其实他的本质还是调用了函数,即构造函数。 构造函数是一个特殊的成员函数,名字与类名相同,在创建类的对象时编译器会自动调用,保证每一个数据成员都有一个合适的初值,在对象的生命周期内只调用一次。 特性:

函数名与类名相同没有返回值对象实例化时编译器自动处理对应的构造函数构造函数也支持重载 class Data { public: //无参构造函数 Data() {} //带参构造函数 Data(int year, int month, int day) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; }; void fun1() { Data a;//调用无参构造函数 Data b(2020, 3, 18);//调用带参构造函数 Data c();//错误的调用 }

构造函数本质还是一个函数,可以支持函数重载的,如果想要通过无参构造函数来创建对象的时候,对象名的后面不用跟上括号(第三种写法),否则就不是函数调用,而是函数声明了。

如果类中没有显示我们定义的构造函数,那么C++编译器会自动生成一个无参的默认构造函数。而如果我们定义了一个构造函数,那么编译器将不再生成,在使用的时候直接调用用户自定义的构造函数。默认构造函数可以是无参的构造函数,也可以是全缺省的构造函数,并且默认构造函数只能有一个。 class Data { public: //无参构造函数 Data() { _year = 2020; _month = 3; _day = 19; } //全缺省构造函数 Data(int year = 2020, int month = 3, int day = 19) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };

我们知道,全缺省的函数也可以不用传参,要是我们在定义全缺省构造函数的同时,又调用一个无参构造函数,这样编译器可以通过吗?答案是显而易见的,编译器会报"指定了多个默认构造函数",以及"对重载函数的调用不明确"的错误。 同样的都是无参数可以通过的,但是放在一个类中编译器不知道应该执行哪一个函数,就会报错,所以说两种默认构造函数在同一个类中只能存在一种。

在这里插入图片描述 7. 如果我们在一个类中没有定义构造函数,编译器自动生成的默认构造函数会完成什么作用? 在这里插入图片描述 事实证明他没有完成我们想要的初始化操作,成员变量的结果依旧是一个随机值,那么这时候自动生成的默认构造函数开起来好像没有什么用。。。 而C++的类型有自定义类型和内置类型(基本类型)。内置类型就是在语法上已经存在的类型,就像int,char,double等等我们可以直接使用的类型;另一种就是我们自己定义的类型,就像struct,union,class等等。 在这里插入图片描述 我们发现编译器生成的默认构造函数可以对自定义类型的成员 _time进行访问,并调用time类的默认构造函数。

析构函数

析构函数的功能与构造函数相反,析构函数不是完成对象的销毁,因为局部对象的销毁工作是由编译器完成的。而类对象在销毁时会自动调用析构函数,以便完成类的一些资源清理工作。他是特殊的成员函数。 特性:

析构函数的函数名是在类名的前面加~字符析构函数没有参数也没有返回值一个类有且只有一个析构函数。同构造函数一样,如果未定义,编译器会自动生成一个默认的析构函数。在对象的生命周期结束的时候,C++编译系统会自动调用析构函数。 class arr { public: arr(int capacity = 10) { _capacity = capacity; _size = 0; _a = (int*)malloc(sizeof(int)* _capacity); } ~arr() { if (_a) { free(_a); // 释放堆上的空间 _a = NULL; // 将指针置为空 _capacity = 0; _size = 0; } } private: int* _a; int _size; int _capacity; }; 同构造函数一样,编译器默认生成的析构函数也会调用自定义类型的成员的析构函数。

在这里插入图片描述

拷贝构造

构造函数只有单个形参,这个参数是对他自己类型的对象的一个引用(一般使用const修饰),从而创造出另一个一模一样的对象。在用已存在的类的类型对象创建新对象时由编译器自动调用。 特性:

拷贝构造函数是构造函数的一个重载形式,函数名同类名,不同的是他只有类本身类型的一个参数 class Data { public: Data(const Data& d) { _year = d._year; _month = d._month; _day = d._day; } private: int _year; int _month; int _day; }; 拷贝构造函数的参数只有一个并且必须使用引用传参,使用传值的方式会引发无穷递归调用。

在这里插入图片描述

若未显示定义,系统生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储,并按照字节序完成拷贝,这种拷贝叫做浅拷贝或者值拷贝。既然编译器可以默认生成的拷贝构造函数就可以完成字节序的拷贝,我们还需要自己实现吗?如果成员变量中没有指针类型的变量,我们就可以不用自定义拷贝构造函数,但是如果有指针类型的成员变量,在默认的浅拷贝时会出错,这时就需要深拷贝。 在这里插入图片描述

我们可以看到,在没有return 0之前,a和b类的内容都是一模一样的,两个指针变量指向的是同一块内存地址。然后当return 0之后,由于a和b类在栈中的存储的顺序,先处理的是b类,直接调用析构函数,这时发现a类也被析构了,但是问题是这时还没有调用a类的析构函数。 所以说,当b类析构函数执行结束后,再次调用a类的析构函数就会造成空指针的访问,肯定会出错的,这个时候默认的浅拷贝就出现了问题,就需要我们自定义的深拷贝了(后面再说)。

运算符重载

在C++中引入了运算符的重载,这是一个具有特殊函数名的函数,同时也具有返回值,函数名以及参数列表,其返回值类型和参数列表都和普通函数差不多。 意义

为了增强程序的可读性,让自定义类型可以像内置类型一样使用运算符。

使用方式

返回值类型 operator操作符(参数列表)

注意

不能通过连接其他符号来创建新的操作符,就像 operator@,这是错误的。重载操作符必须有一个类的类型或者枚举类型的操作数用于内置类型的操作符,他的含义不能改变,就像 内置的整形+,不能在函数内部使用-等其他操作,也就是不能把函数的本意改变。作为类成员的重载函数时,他的形参可以比操作数的数目少1个,是因为成员函数的操作符有一个默认的形参this指针,可以当做一个形参。.*(成员指针访问运算符),::(域运算符),sizeof(长度运算符),?:(条件运算符),. (成员访问运算符)这五个运算符不可以被重载。 class Data { public: //类中 bool operator==(Data& d2) { return _day == d2._day &&\ _month == d2._month &&\ _year == d2._year; } //private: int _year; int _month; int _day; }; //类外 bool operator==(const Data& d1, const Data& d2) { return d1._day == d2._day &&\ d1._month == d2._month &&\ d1._year == d2._year; } int main() { Data d1; Data d2; d1 == d2; operator==(d1, d2); return 0; }

如果我们把运算符重载的函数写在类的外面时,只能访问公有的成员变量,私有的不可以访问,只能通过函数来访问。 而调用运算符重载函数,有两种方式,一种就是像我们调用普通函数一样去使用,第二种就是像我们使用变量那种形式进行简洁的使用。 在这里插入图片描述 通过查看,发现两种使用方式在底层调用子程序的时候,都是调用的同一个子程序。所以说,使用运算符重载还是比较简单,方便的。 特点:

参数类型有返回值还需要检测是否自己给自己赋值返回*this一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝(浅拷贝)。 int main() { Data d1; Data d2 = d1;//这里调用的是拷贝构造,不是运算符重载 return 0; }

拷贝构造是一个已经存在的类给另一个不存在的类拷贝一个数据,运算符重载是给两个都存在的类之间的互相赋值。

const 修饰类的成员变量

将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。 在这里插入图片描述 在使用const 的时候,需要注意,const变量的权限只能缩小,不能放大。以日期类为例

赋值变量类型待赋值变量类型是否可行const Date*(只读)const Date*(只读)可行Date*(可读可写)Date*(可读可写)可行const Date*(只读)Date* (可读可写)不可行Date*(可读可写)const Date*(只读)可行 取地址及const取地址操作符重载 class Date { public : Date* operator&() { return this ; } const Date* operator&()const { return this ; } private : int _year ; // 年 int _month ; // 月 int _day ; // 日 };

这两个默认成员函数可以返回这个类this指针的地址,一般用默认生成的就好了。如果想让用户获取到指定的内容,可以稍加修改自定义弄一个。

默认函数实现日期类 class Date { public: // 获取某年某月的天数 int GetMonthDay(int year, int month) { static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int day = days[month];//拿到当前月除了2.29的最大日期 //如果出现2月29日 if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) { day += 1; } return day; } // 全缺省的构造函数 Date(int year = 1900, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } // 拷贝构造函数 // d2(d1) Date(const Date& d) { _day = d._day; _month = d._month; _year = d._year; } // 赋值运算符重载 // d2 = d3 -> d2.operator=(&d2, d3) Date& operator=(const Date& d) { _day = d._day; _month = d._month; _year = d._year; return *this; } // 析构函数 ~Date() { _year = 0; _month = 0; _day = 0; } // 日期+=天数 Date& operator+=(int day) { //如果日期是负数 if (day _day -= maxDay;//减掉当前月的天数 _month++;//月+1 //如果月超了,年+1,月变成1月 if (_month == 13) { _month = 1; _year++; } maxDay = GetMonthDay(_year, _month); } return *this; } // 日期-=天数 Date& operator-=(int day) { //如果要减的日期是负数 if (day _month--;//当前月份-1 //如果没得减,返回上一年 if (_month == 0) { _month = 12; _year--; } int maxDay = GetMonthDay(_year, _month); _day += maxDay; } _day -= day; return *this; } // 日期+天数 Date operator+(int day) { Date tmp(*this); //tmp.operator+=(day); tmp += day; return tmp; } // 日期-天数 Date operator-(int day) { Date tmp(*this); //tmp.operator-=(day); tmp -= day; return tmp; } // 前置++ , ++i Date& operator++() { *this += 1; return *this; } // 后置++ ,为了区分前置++,加一个参数 i++ Date operator++(int)//Date operator++(int i) //也可以这样 { Date tmp(*this);//拷贝++之前的值 *this += 1; return tmp; } // 后置-- i-- Date operator--(int) { Date tmp(*this);//拷贝++之前的值 *this -= 1; return tmp; } // 前置-- --i Date& operator--() { *this -= 1; return *this; } // >运算符重载 bool operator>(const Date& d) { 根据年直接比 //if (_year > d._year) // return true; 年相等比月 //if (_year == d._year && _month > d._month) // return true; 年月相等比天 //if (_year == d._year && _month == d._month && _day > d._day) // return true; if ((_year > d._year) || \ (_year == d._year && _month > d._month) || \ (_year == d._year && _month == d._month && _day > d._day)) return true; return false; } // ==运算符重载 bool operator==(const Date& d) { return _day == d._day &&\ _month == d._month &&\ _year == d._year; } // >=运算符重载 inline bool operator >= (const Date& d) { //即不小于 小于为假 return !(*this //即不大于,大于为假 return !(*this > d); } // !=运算符重载 bool operator != (const Date& d) { //即等于为假 return !(*this == d); } bool LeapYear(int year) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return true; return false; } // 日期-日期 返回天数 int operator-(const Date& d) { Date small; Date big; if (*this > d) { big = *this; small = d; } else { big = d; small = *this; } //累加法 int numDay = 0; while (small!=big) { small++; numDay++; } return numDay; } void Printf() { cout


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭