C++之类和对象的中篇

这篇具有很好参考价值的文章主要介绍了C++之类和对象的中篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk

      ⸝⋆   ━━━┓
     - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━  ➴ ⷯ

本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。

👑💎💎👑💎💎👑 
💎💎💎自💎💎💎
💎💎💎信💎💎💎
👑💎💎 💎💎👑    希望在看完我的此篇博客后可以对你有帮助哟

👑👑💎💎💎👑👑   此外,希望各位大佬们在看完后,可以互相支持,蟹蟹!
👑👑👑💎👑👑👑 

目录:
一:类的6个默认成员函数
二:构造函数
三:析构函数
四:拷贝构造函数
五:赋值运算符重载
六:const成员函数
七:取地址以及const 取地址操作符重载

思维导图:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

1:类的6个默认成员函数

1)空类:一个类里面什么成员也没有,既称之为空类

2)一个空类里面并不是什么也没有,编译器会默认生成6个默认成员函数(不需要用户自己定义,编译器隐式调用的)

3)

6个默认成员函数

构造函数:主要就是完成函数的初始化

析构函数:对资源的清理

拷贝构造函数:使用同类对象初始化并创建同类对象

赋值运算符重载:把一个对象赋值给另一个对象

const成员函数:

取地址以及const 取地址操作符重载:普通对象和const 对应的对象进行取地址

2:构造函数

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

对于C++而言,我们可以不用 手动调用初始化函数,构造函数就可以完成这一工作

在创建对象 的同时编译器会默认自动调用构造函数

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

关于构造函数基本使用方法:

1)构造函数 的名字和类的名字相同

2)构造函数没有返回类型(注意没有返回类型不代表就写成void )

3)构造函数支持函数重载(可以有多个初始化的函数)

4)对象创建的同时编译器默认自动调用构造函数

5)有参的构造函数以及无参的构造函数书写的区别

无参构造函数 在调用的时候后面是不能添加 ()

有参构造函数在创建对象的同时就给出对应的参数即可

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

当用户自己没有定义构造函数的时候,编译器会默认生成一个构造函数

只不过此时是隐式调用构造函数

至于结果为什么是随机值,下面会继续讲解

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

6)编译器生成的默认构造函数:对对象初始化的时候为什么是随机值??

相信这是不少老铁们的疑惑

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

这是因为编译器底层对类型做了一些特殊的处理:

对于内置的类型(基本类型)(比如int ,char,float,double,指针等等):编译器在调用构造函数的时候不会对类的成员进行处理

但是对于那些自定义类型:struct , class ,enum, unio等等,编译器在调用构造函数的时候对这些成员会进行处理

栗子见下:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

对于默认构造函数的理解:

相信有不少老铁们会认为:只有编译器生成的构造函数才是 默认构造函数,那你就大错特错了

有参的构造函数,无参的构造函数,编译器生成的构造函数都是默认构造函数

 针对编译器不能对内置类型做处理这一问题,引出了全缺省的构造函数

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

那么问题又来了:当无参的构造函数和全缺省的构造函数同时存在,并且对象也没有给出对应 的参数,编译器是否可以编译通过呢???

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

自然是不言而喻的,不能通过:因为此时发生歧义了,编译器也不知道自己到底是调用无参的构造函数还是调用全缺省的构造函数

所以:对于无参的构造函数以及全缺省的构造函数只能存在一个(一般建议:选择全缺省的构造函数)

3:析构函数

在学习数据结构链表等知识章节的时候,我们总是频繁的调用初始化函数,销毁函数,在C++里面,我们把资源的释放交给析构函数来进行处理,析构函数是和构造函数功能相反的一个函数,但是他们之间又有许多的共同点

析构函数基本特性 

 1)析构函数名字和类名一样,但是需要在类名前面加上一个 ~(方便编译器与构造函数进行区分)

2)没有返回类型也没有参数(不需要写 void )

3) 编译器会自动调用析构函数(当前对象销毁时候调用)

4)析构函数不支持函数重载

5)当用户没有显示调用析构函数的时候,编译器会在对象生命周期结束的时候自动调用(隐式调用)

6)和构造函数一样:编译器对内置类型(基本类型)的类的成员不做处理,对自定义类型的成员做处理

7) 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
    有资源申请时,一定要写,否则会造成内存泄漏

关于析构函数 的基本使用如下:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

编译器隐式调用Date的析构函数,显示调用Time的析构函数(用户没有定义析构函数)的栗子:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

析构函数是否需要写:看情况分析:

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

4:拷贝构造函数
4.1概念:

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

4.2 特性:

1)拷贝构造函数是构造函数的一个重载

2 拷贝构造函数的参数只有一个且必须是类类型对象的引用(注:采用传值传参,会出现无限递归的情况)

3)当用户没有定义拷贝构造函数的时候编译器会调用默认 的拷贝构造函数(隐式),但是这个默认的拷贝构造函数只能对内置类型进行浅层 拷贝(值拷贝),当涉及到自定义类型的成员的时候,浅层拷贝就会有问题

4)类中如果没有涉及资源申请时,拷贝构造函数可写可不写;涉及到资源申请时,则拷贝构造函数必须写,否则编译器就是执行浅层拷贝(出现一些问题)。

拷贝构造函数的基本使用栗子:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

注意以下是错误使用范例:

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 浅层拷贝应用

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

深层拷贝:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

注意深层拷贝不再是简简单单的拷贝那么简单了,这时候涉及到析构函数先后调用的问题

分析:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

问题不仅仅是体现这方面:当Pop的时候也是有问题

 关于拷贝构造函数的综合应用场景:

class Date
{
public:
	Date(int year, int minute, int day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d):" << this << endl;
	}
	~Date()
	{
		cout << "~Date():" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date Test(Date d)
{
	Date temp(d);//用已经存在的对象d初始化temp,就需要调用拷贝构造函数
	cout << "&temp:" << &temp << endl;
	return temp;//返回类型:是一个类,就需要调用拷贝构造函数,注意此时虽然是返回一个局部变量,但是编译器是借助创建一个临时变量来返回的 
}
int main()
{
	//拷贝构造函数适应场景:1)已经存在的类对象创建一个新的类对象  2)函数返回类型是类的   3)函数参数类型:类的类型
	Date d1(2022, 1, 13);//调用构造函数创建d1这个对象,注意拷贝函数是一个特殊的构造函数(构造函数的一个重载)
	cout << "&d1:" << &d1 << endl;
	Test(d1);//传值传参,就需要调用拷贝 构造函数
	return 0;
}

对以上结果分析见下:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

5:赋值运算符重载
5.1运算符重载

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

以实现 '>'  '<'  '<='   '>='   '=='   '!= '运算符的重载为例吧:

注意:对于bool 类型,true一般以1代表真,false以0代表假

当把重载函数定义在类里面的时候,此时默认隐藏一个参数,也就是this指针,这个指针指向左操作数

 代码:

class Date
{
public:
	int _year;
	int _month;
	int _day;
	void Print()
	{
		cout << _year << '/' << _month << '/' << _day << endl;
	}
	Date(int year = 2024, int month = 3, int day = 26)//全缺省的构造函数(对于内置类型不做处理,对于自定义类型做处理)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//注意对于Date这个类不需要写拷贝构造函数,编译器可以进行处理
	Date(const Date& d)//拷贝构造函数(对应内置类型是做浅层拷贝,自定义类型深层拷贝)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	// d1 > d2 *this 默认指向运算符的左操数,此时d是d2的引用
	bool operator>(const Date& d)
	{
		if (_year > d._year)
		{
			return true;
		}
		else if (_year == d._year && _month > d._month)
		{
			return  true;
		}
		else if (_year == d._year && _month == d._month && _day > d._day)
		{
			return true;
		}
		else 
			return false;
	}
	// d1 == d2
	bool operator==(const Date& d)
	{
		return _year == d._year && _month == d._month && _day == d._day;
	}
	bool operator!=(const Date& d)
	{
		//直接复用之前代码
		return !(*this == d);
	}
	//d1 >= d2 ===> d1 > d2 || d1 == d2
	bool operator>=(const Date& d)
	{
		return(((*this) > d) || (*this) == d);
	}
	// d1 <= d2
	bool operator<= (const Date& d)
	{
		//对 . 进行取反
		return !(*this > d);
	}
};
int main()
{
	Date d1(2024, 11,26);//调用构造函数进行实例化
	Date d2;// 只不过是用全缺省函数进行初始化
	cout << (d1 <= d2) << endl;//编译器会自动转换成调用这个!= 运算符重载函数 d1.operator(d2)

	return 0;
}
5.2 赋值运算符重载
class Time
{
public:
	int _hour;
	int _min;
	int _sec;
	Time(int hour = 22, int min = 22, int sec = 22)//全缺省的构造函数
	{
		_hour = hour;
		_min = min;
		_sec = sec;
	}
	Time(const Time& t)//拷贝构造函数
	{
		_hour = t._hour;
		_min = t._min;
		_sec = t._sec;
	}
	void operator=(Time t)// 对 = 这个运算符重载
	{
		_hour = t._hour;
		_min = t._min;
		_sec = t._sec;
	}
	
};
int main()
{
	Time t1(22, 12, 20);
	Time t2;
	t2 = t1;
	cout << t1._hour << ':' << t1._min << ':' << t1._sec << endl;
	cout << t2._hour << ':' << t2._min << ':' << t2._sec << endl;

	return 0;
}

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

5.3日期类的实现
5.3.1实现日期+天数的函数

日期+天数 可以得到一个精确的日期

2024,3, 27 +  50 这个涉及到进位的问题(如同加法的运算一样)

此时天数是 77 显然是大于3月份的天数

进位 & 并减去是3月份的天数,

:2024 ,4 ,46,同理,大于4月份的天数

2024,5,16 此时的满足5月份的天数要求

最终结果:2024,5,16

分析:

1)写一个获取当前月份的天数的函数

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

2)用循环判断当前月份的天数是否满足要求

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

运行结果:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

和网上求的一样,觉得没有啥问题

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

当我们连续调用 += 这个函数的时候,问题就来了

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

正确答案:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

其实简单分析一下,就知道问题所在了:第一次调用是以 d1为参考对象进行50天后的日期推算。第二次调用虽然是以d1为参考对象,但是此时的d1不再是2024,3,27了,因为实现的+=这个运算符重载的函数改变了d1

改进之后的代码:实现 + 的运算符重载即可

代码:

Date Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year,_month,_day))
	{
		if (_month >= 13)
		{
			_month = 1;
			_year++;
		}
		_day -= GetMonthDay(_year, _month, _day);//减去当月的天数
		_month++;
	}
	return *this;//返回*this,每次调用都会改变当前的对象
	//注意当这样写有bug
	//如果连续调用进行日期相加的话,就出问题

}
Date Date::operator+(int day)
{
	//对上面的+=改进
	Date tmp(*this);//对*this 进行拷贝一份
	tmp += day;//直接调用 +=的函数
	return tmp;
	//弊端:涉及到拷贝的调用
}

运行结果:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

对最后一个结果进行验证:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 5.3.2 日期 - 日期的函数

在实现日期- 日期函数之前,先写一个日期 - 天数的函数

这个分析过程和日期+天数一样,只不过这里是进行借位的运算:

2024,2,15 - 50

用当前月份的天数 - 50 =  - 35  < 0

此时向前借位:注意这里借的是 1月份的天数,既不是借的2月份的天数,也不是借的3月份的天数

用借来月份的天数 + 当前天数 - 35 = - 4 < 0

依然进行借位:借的的前一年,也就是 2023年的12月份的天数 31 + (-4) = 27

注意这里在代码实现上的细节:对应的年要 - -,对应的月份要跟新到12 月份

也就是最终结果:2023,12,27

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

对于这个代码其实还是有一点 的Bug,连续调用这个 - = 运算符重载函数的时候,对应 的结果会觉得比较怪:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

通过代码调试就知道了:- = 这个运算符重载函数每次调用都会对当前的参考对象进行改变

优化之后的代码:

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

运行结果:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 日期 - 日期:

// d2 - d1 = 天数
int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	Date tmp = d;
	//找出较大的日期
	if (max < min)
	{
		tmp = max;
		max = min;
		min = tmp;
	}
	//找出较小的那个日期,对这个较小的日期进行++,直到与较大的日期相等
	int count = 0;
	while (min < max)
	{
		count++;
		++min;
	}
	return count;
}

 C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 运行结果:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

6:const成员函数
定义

const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
 

应用

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 此时定义2个Date 的对象,区别就是有无const 进行修饰

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

通过运行结果看出:都可以进行调用Print这个函数

思考以下几个问题

        1. const对象可以调用非const成员函数吗?
        2. 非const对象可以调用const成员函数吗?
        3. const成员函数内可以调用其它的非const成员函数吗?
        4. 非const成员函数内可以调用其它的const成员函数吗?

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

      1. const对象可以调用非const成员函数吗?

不能;此时会造成权限的放大
        2. 非const对象可以调用const成员函数吗?

可以;权限可以缩小
        3. const成员函数内可以调用其它的非const成员函数吗?

不能
        4. 非const成员函数内可以调用其它的const成员函数吗?

可以,权限缩小

7:取地址以及const 取地址操作符重载

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

注意这2个函数,对于第二个函数而言:他是一个const成员函数,返回值类型 const Date*

一般可以不写此函数,编译器会默认生成

 运行结果:

C++之类和对象的中篇,javascript,算法,开发语言,c++,c语言,数据结构

 结语:

 OK~,以上就是我今日要为各位share的,对于类这个模块的学习非常重要,而且知识点也特别零散。希各位都可以有所收获从这篇文章里面,当然也是有许多不足之处,欢迎各位大佬随时指出,谢谢支持!文章来源地址https://www.toymoban.com/news/detail-854991.html

到了这里,关于C++之类和对象的中篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】类和对象(中篇)

    在往期 类和对象(上篇) 中,我们初步接触了C++中的类和对象,接下来我会和大家分享有关这个知识点更多的内容~ 如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成默认成员函数。 默认成员函数:用户

    2024年02月15日
    浏览(51)
  • 【C++笔记】C++之类与对象(上)

    C++的一个显著特征就是兼容C语言,所以C++把结构体“升级”成了“类”,之所以是“升级”是因为,在C++中的结构体及支持以前C语言的结构体的玩法,也可以支持C++中类的玩法。 例如单链表节点这个类,我们既可以写成纯C版本: 用纯C的写法,我们每次要定义一个节点变量

    2024年02月12日
    浏览(38)
  • c++学习之类与对象3

    目录 成员变量和函数的存储 this指针 this指针的工作原理 this指针的应用 const修饰的成员函数 友元 友元的语法 1.普通全局函数成为类的友元 2.类的某个成员函数作为另一个类的友元 整个类作为另一个类的友元 运算符重载 1 运算符重载的基本概念 2 重载加号运算符 3 重载左移

    2023年04月21日
    浏览(42)
  • 【C++初阶】之类和对象(中)

    📃 博客主页: 小镇敲码人 💞 热门专栏:C++初阶 🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏 🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎 ❤️ 什么?你问我

    2024年04月13日
    浏览(47)
  • 【C++初阶】之类和对象(下)

    📃 博客主页: 小镇敲码人 💞 热门专栏:C++初阶 🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏 🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎 ❤️ 什么?你问我

    2024年04月16日
    浏览(83)
  • C++初阶之类和对象(中)

    如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。 默认构造函数(Default Constructor) :如果没

    2024年02月12日
    浏览(31)
  • C++初阶之类和对象(下)

    在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化, 构造函数体中的语句只能将其称为赋初值 ,而不能称作初始化。因为 初始化只能

    2024年02月13日
    浏览(31)
  • C++好难(3):类和对象(中篇)

    类的6个默认成员函数 构造函数 析构函数 拷贝构造函数 赋值运算符重载 const成员函数 取地址及const取地址操作符重载 目录 【本章目标】 1.类的6个默认成员函数 2.构造函数 2.1概念 2.2构造函数的特性 特性一 特性二 特性三 特性四 特性五 特性六 特性七 2.3总结 3.析构函数 3.

    2024年02月03日
    浏览(35)
  • 【入土级】详解C++类&对象(中篇)

    目录 前言:类的6个默认成员函数 一, 构造函数 1. 概念 2. 特性 二, 析构函数 2.1 概念 2.2 特性 2.3 牛刀小试  三, 拷贝构造函数 3.1概念 3. 2 特点 四, 赋值运算符重载 4. 1 运算符重载  五, const成员函数 六,取地址及const取地址操作符重载 七,练习——实现日期计算器

    2024年02月05日
    浏览(42)
  • 0基础入门C++之类和对象下篇

    1.再谈构造函数 首先我们先来回忆一下构造函数: 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次 。即构造函数其实就是帮我们对类的成员变量赋一

    2024年02月11日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包