6.C++面向对象3(默认成员函数,构造函数,析构函数详解)

⭐本篇为C++学习第6章,主要了解默认成员函数,构造函数,析构函数

⭐本人Gitee C++代码仓库:yzc的c++学习: 小川c++的学习记录 - Gitee.com 

目录

一. 类的6个默认成员函数

二. 构造函数

三.析构函数

 四 多个对象调用构造函数和析构函数的顺序

五. 下章重点

5.1 拷贝构造函数

5.2 运算符重载和赋值运算符重载


一. 类的6个默认成员函数

        对于一个空类来说,其大小是1,但是空类中真的什么都没有吗??

其实,任何类在什么都不写时候,编译器会默认生成6个成员函数

1. 完成类对象的初始化和清理工作:

        构造函数用于完成对象的初始化

        析构函数用于完成对象的清理

2. 完成类对象的拷贝和赋值:

        拷贝构造用于完成类初始化时候使用一个对象拷贝另一个对象

        赋值运算符重载用于使用一个对象赋值给另一个对象

3. 取地址重载:

        普通对象和const对象的取地址重载,我们很少自己实现

注意:

1. 默认生成的构造函数和析构函数。针对成员变量:内置类型不会处理,但是成员变量是其他类的话,会调用这个类的构造函数。

2.默认生成的拷贝构造和赋值运算符重载。只会按字节序拷贝(浅拷贝)

也就是说,很多类不需要我们去实现这些函数,编译器会自动生成。

但是对于拷贝构造和赋值运算符重载。由于C++默认生成的是浅拷贝,这会造成错误。如:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

class A
{
public:
	A(int a = 0)
	{
		_a = &a;
	}
	~A()
	{
		free(_a);
	}
private:
	int* _a;
};

int main()
{
	A a;
	A b(a);
	A c(2);
	a = c;
	return 0;
}

由于默认的浅拷贝,对象a,b,c中的_a指向同一块空间。

当调用析构函数的时候,这块空间会被析构多次,就会报错。

所以,我们需要自己实现拷贝函数和赋值运算符重载的深拷贝,以避免出现这种问题。

二. 构造函数

        我们以时间类为例,逐步讲解。

我们知道,在C语言可以在结构体中实现一个Init函数,用于初始化结构体

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

class Time
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void print()
	{
		cout << _year << "/" << _month << "/" << _day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Time t1;
	t1.Init(2024, 9, 24);//完成初始化工作
	t1.print();
	return 0;
}

但是这种方法有点麻烦,我们能不能在创建对象的时候就初始化呢?

这个时候就需要使用构造函数来完成这个功能

构造函数的名称和类名是一样的!

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

class Date
{
public:
	//无参的构造函数
	Date()
	{
		_year = 0;
		_month = 0;
		_day = 0;
	}
	//有参的构造函数
	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 t1;
	Date t2(2024, 9, 24);
	t1.print();
	t2.print();
	return 0;
}

运行结果: 

使用构造函数,我们能够方便地对对象进行初始化

对于有参和无参构造函数,我们还能使用缺省值的特点来合并。

	//带缺省值的构造函数,合并了有参构造和无参构造
	Date(int year = 0, int month = 0, int day = 0)
	{
		_year = year;
		_month = month;
		_day = day;
	}

注:

1. 构造函数(在对象初始化调用的函数) ---> 完成类的初始化工作,

a 函数名和类名相同,无返回值

b 对象初始化的时候自动调用类中的构造函数

c 构造函数可以重载,完成不同对象的初始化(有参和无参)

d 如果类中没有自定义构造函数,编译器会默认生成一个无参的构造函数

e 如果用户自定义了一个有参的构造函数,那么系统不会自动生成,这个时候需要用户自己定义一个无参的默认构造函数,

默认构造函数针对内置类型成员变量没有初始化,针对自定义类成员变量,会调用其的构造函数进行初始化,如:

class A
{
public:
	A(int a = 0)
	{
		_a = a;
	}

private:
	int _a;
};

class B
{
	int _b;
	A a;
};

B的默认构造函数会调用A的相应构造函数

在实际应用中,我们更倾向于使用全缺省的默认构造函数

f 无参的构造函数和全缺省的构造函数统称为默认构造函数,但是默认构造函数只能存在一个,所以这两个函数只能定义一个,两个同时存在会造成歧义

三.析构函数

        析构函数用于完成对象的清理工作。当对象的生命周期结束后,就会自动调用。

class Date
{
public:
	//带缺省值的构造函数,合并了有参构造和无参构造
	Date(int year = 0, int month = 0, int day = 0)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//析构函数,由于没有使用new,malloc等开辟空间。函数内部为空
	~Date()
	{}

	void print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

注:

析构函数(用于完成对象的清理工作)

a 析构函数无返回值,无参数。

b 析构函数名字的在类名前加~

c 一个类只有一个析构函数,若用户没有自定义,编译器会默认生成一个

d 当对象的生命周期结束后,会自动调用其析构函数

e 和构造函数类似,默认生成的构造函数不会处理内置类型,对于类成员变量,会调用该类的析构函数

f 析构函数完成的是对象的清理,不是对象的销毁

g 注意析构的顺序,后创建的对象先析构

 四 多个对象调用构造函数和析构函数的顺序

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{cout << "调用A构造函数A()" << endl;}

	~A()
	{cout << "调用A析构函数~A()" << endl;}
};

class B
{
public:
	B()
	{cout << "调用B构造函数B()" << endl;}

	~B()
	{cout << "调用B析构函数~B()" << endl;}

	A a;
};

int main()
{
	A a1;
	B b1;
	A a2;
	B b2;
	return 0;
}

分析一下,上面的的代码输出是什么??

应该是:

调用A构造函数A()        //a1

调用A构造函数A()        //b1

调用B构造函数B()        //b1

调用A构造函数A()        //a2

调用A构造函数A()        //b2

调用B构造函数B()        //b2

调用B析构函数~B()        //b2(后创建,先析构)        

调用A析构函数~A()        //b2

调用A析构函数~A()        //a2

调用B析构函数~B()        //b1

调用A析构函数~A()        //b1

调用A析构函数~A()        //a1

运行结果如下

        即构造函数先完成类内对象的构造函数,在调用自己的构造函数。

        析构函数先完成自己的析构再去调用类内成员的析构函数。

五. 下章重点

5.1 拷贝构造函数

5.2 运算符重载和赋值运算符重载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子真甜~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值