C++第六弹---类与对象(三)

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

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】

目录

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

2、构造函数

2.1、概念

2.2、特性

3、析构函数

3.1、概念

3.2、特性

3.3、调用顺序

总结


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


如果一个类中什么成员都没有,简称为空类
空类中真的什么都没有吗?并不是,任何类在什么都不写时编译器会自动生成以下6个默认成员
函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数
 

class Date {};

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

2、构造函数

2.1、概念


对于以下Date类:

#include<iostream>
using namespace std;
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(2022, 7, 5);
	d1.Print();
	Date d2;
	d2.Init(2022, 7, 6);
	d2.Print();
	return 0;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

 对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置
信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?

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

2.2、特性


构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
务并不是开空间创建对象,而是初始化对象
其特征如下:

1. 函数名与类名相同。
2. 无返回值(返回值不是void,而是不需要返回值)。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。

#include<iostream>
using namespace std;
class Date
{
public:
	// 1.无参构造函数
	Date()
	{}
	// 2.带参构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1; // 调用无参构造函数,不需要加括号
	Date d2(2015, 1, 1); // 调用带参的构造函数
	// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,加括号就成了函数声明
	Date d3();//声明了d3函数,该函数无参,返回一个日期类型的对象
	// warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
	return 0;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

注意:调用无参够赞函数或者全缺省构造函数,不需要加函数的括号。 

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

 

#include<iostream>
using namespace std;
class Date
{
public:
	
	// 如果用户显式定义了构造函数,编译器将不再生成
	Date(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类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数
    // 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成
    // 无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用
	Date d1;
	return 0;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

6. 关于编译器生成的默认成员函数,很多uu会有疑惑:不实现构造函数的情况下,编译器会
生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默
认构造函数,但是d对象_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;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在
类中声明时可以给默认值。

 

#include<iostream>
using namespace std;
class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
		void Print()
		{
			cout << _year << "-" << _month << "-" << _day << endl;
		}
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	d.Print();
	return 0;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个

注意:

无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
是默认构造函数。

 

#include<iostream>
using namespace std;
class Date
{
public:
	Date()//无参默认构造
	{
		_year = 1900;
		_month = 1;
		_day = 1;
	}
	Date(int year = 1900, int month = 1, int day = 1)//全缺省默认构造
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
// 以下测试函数能通过编译吗?
int main()
{
	Date d1;//默认构造只能存在一个,此处有两个默认构造函数
	return 0;
}

答案是不能编译通过,因为默认构造函数只能存在一个,上述代码存在无参构造函数和全缺省构造函数。 

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

注意:构造函数遵循先定义先构造原则。

3、析构函数

3.1、概念


通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?

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

3.2、特性


析构函数是特殊的成员函数,其特征如下:

1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

在我们前面学习栈的实现的时候,动态开辟后的内存需要手动进行释放,但是我们很有可能会忘记释放,因为即使不释放空间,程序也可以正常运行。如果使用析构函数,那么会自动调用,能够有效减少忘记释放的可能。

#include<iostream>
using namespace std;
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);
}

通过使用析构函数实现的栈,对象的生命周期结束后,会自动调用析构函数,也有效减少忘记释放空间的问题,但是前提是我们在类里要手动实现一个释放栈空间的析构函数。 

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

 

#include<iostream>
using namespace std;
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()

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数? 

因为:main方法中创建了Date对象d,而d中包含4个成员变量,其中_year, _month,_day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。但是:main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数

注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数 


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

3.3、调用顺序

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1)
	{
		_year = year;
	}

	~Date()
	{
		cout << "~Date()->"<<_year<< endl;
	}
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
};
void func()
{
	Date d3(3);//局部对象
	static Date d4(4);//局部的静态
}
Date d5(5);//全局对象
static Date d7(7);//全局静态
Date d6(6);
static Date d8(8);

// 局部对象(后定义先析构) -》 局部的静态 -》全局对象(后定义先析构)
int main()
{
	Date d1(1);//局部对象 
	Date d2(2);
	func();

	return 0;
}

C++第六弹---类与对象(三),C++详解,c++,算法,开发语言,c语言

析构函数执行顺序:局部对象(后定义先析构) -》 局部的静态 -》全局对象(后定义先析构)

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!文章来源地址https://www.toymoban.com/news/detail-842500.html

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

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

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

相关文章

  • C++初阶类与对象(二):详解构造函数和析构函数

    C++初阶类与对象(二):详解构造函数和析构函数

    上次为类与对象开了一个头:C++初阶类与对象(一):学习类与对象、访问限定符、封装、this指针 今天就来更进一步 如果一个类中什么成员都没有,简称为空类。 空类中并不是什么都没有,任何类在什么都不写时,编译器会 自动生成上面6个默认成员函数 。 默认成员函数

    2024年01月19日
    浏览(16)
  • 【浅尝C++】继承机制=>虚基表/菱形虚继承/继承的概念、定义/基类与派生类对象赋值转换/派生类的默认成员函数等详解

    【浅尝C++】继承机制=>虚基表/菱形虚继承/继承的概念、定义/基类与派生类对象赋值转换/派生类的默认成员函数等详解

    🏠专栏介绍:浅尝C++专栏是用于记录C++语法基础、STL及内存剖析等。 🎯每日格言:每日努力一点点,技术变化看得见。 我们生活中也有继承的例子,例如:小明继承了孙老师傅做拉面的手艺。继承就是一种延续、复用的方式。C++为了提高代码的可复用性,引入了继承机制,

    2024年04月10日
    浏览(16)
  • Flutter第六弹 基础列表ListView

    Flutter第六弹 基础列表ListView

    目标: 1)Flutter有哪些常用的列表组建 2)怎么定制列表项Item? 使用标准的 ListView 构造方法非常适合只有少量数据的列表。我们还将使用内置的 ListTile widget 来给我们的条目提供可视化结构。ListView支持横向列表和纵向列表。 ListTile相当于列表项 Item,可以定制列表项内容。

    2024年04月14日
    浏览(11)
  • 力扣刷MySQL-第六弹(详细讲解)

    力扣刷MySQL-第六弹(详细讲解)

     🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页: 小小恶斯法克的博客 🎈该系列文章专栏: 力扣刷题讲解-MySQL 🍹文章作者技术和水平很有限,如果文中出现错误,希望大家能指正🙏 📜 感谢大家的关注! ❤️ 目录  🚀大的

    2024年01月20日
    浏览(10)
  • leetcode数据库题第六弹

    leetcode数据库题第六弹

    https://leetcode.cn/problems/exchange-seats/ 嗯,今天又看了看这个题目,发现用例已经修复了。 https://leetcode.cn/problems/students-and-examinations/ 额。。。统计所有人,所有科目,各进行了几次考核。。。那么人员和科目只能最大化交叉查询了,然后再去关联考试次数。 其实指令是一拖三的

    2024年02月10日
    浏览(11)
  • C++初阶学习第三弹——类与对象(上)——初始类与对象

    C++初阶学习第三弹——类与对象(上)——初始类与对象

    前言: 在前面,我们已经初步学习了C++的一些基本语法,比如内敛函数、函数重载、缺省参数、引用等等,接下来我们就将正式步入C++的神圣殿堂,首先,先给你找个对象 目录 一、类与对象是什么? 二、类的各部分组成 1、类的定义 2、类的访问限定符及封装 3、类的作用域

    2024年04月26日
    浏览(12)
  • [C++]类与对象下篇

    [C++]类与对象下篇

    目录 类与对象下篇::                             1.再谈构造函数                             2.static成员                             3.友元                             4.内部类                             5.匿名对象                             6.拷贝

    2023年04月25日
    浏览(9)
  • C++:类与对象

    类是对一组具有共同属性特征和行为特征的对象的抽象,它可将相关数据和这些数据的操作(函数)组合在一起。 类定义格式: 类名 : class是声明类的,类名是标识符,且在其作用域内必须是唯一的。 注:C++规定,标识符以字母(大小写均可,但区分大小写)或下划

    2024年02月12日
    浏览(13)
  • 【C++】——类与对象(上)

    【C++】——类与对象(上)

    今天我们来学习C++初期最重要的知识点,类与对象,因为类与对象涉及的知识太多,所以我将分为上中下三个部分来为大家讲解类与对象。 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 C++是基于面向对象的,关注的是对象,将一

    2024年02月02日
    浏览(10)
  • [C++] 类与对象(上)

    [C++] 类与对象(上)

      目录 1、前言 2、类的引入 3、类的定义 3.1 类的两种定义方式 4、类的访问限定符 5、类的作用域 6、类的实例化 7、类对象模型 7.1 内存对齐规则 7.1 类对象的存储方式 8、this指针 8.1 this指针的特性 8.2 this指针是否可以为空 C语言是 面向过程 的, 关注 的是 过程 ,分析出求解

    2024年02月15日
    浏览(8)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包