默认成员函数

本文详细解释了C++中的默认成员函数,包括构造函数用于初始化对象,析构函数负责清理资源,拷贝构造函数用于对象赋值,赋值重载允许自定义类型使用等号运算符,以及取地址重载。大部分情况下需自定义构造函数,而拷贝构造与赋值重载在浅拷贝时可使用默认版本。
摘要由CSDN通过智能技术生成

六个默认成员函数

前言:

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

一、构造函数

为了防止写类时,忘记初始化,引入了构造函数

说明:

构造函数的主要任务是初始化对象,并不是开空间创建对象。

特性:

无返回值,函数名和类名相同,构造函数可以重载

没有写构造函数时,编译器会自动生成一个构造函数

class Date
{
public:
	//1.无参的构造函数
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	
	//2.有参的构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	//3.全缺省的构造函数
	Date(int year=1,int month=1,intday=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};

虽然上边是显示三种,但是还有一种我们没有定义,编译器默认生成的;在上边的三种中:
<1> 一、三虽然能构成函数重载,但是编译器依旧报错,因为在不传参情况时调用有歧义
<2> 一、二可以构成函数重载,且不报错
<3> 由此不难看出,第三种,能代替上边的两种,何乐而不为呢?
<4> 第四种,也就是编译器默认生成的那一个对 内置类型(如:int char double)不做处理(被初始化为乱码,不同的编译器结果不同),对自定义类型会调用它的构造函数

class Time
{
public:
	Time(int hour = 1,int minute=1,int second=1)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
	
	//这个t1在初始化时就会去调用 class Time中的构造函数Time
	Time t1;
};

编译器会在创建对象时候自动调用

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

二、析构函数

说明:

析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。主要用于动态开辟的空间的释放 如:malloc realloc 等

特性:

析构函数名是在类名前加上字符 ~, 无参数无返回值类型, 析构函数不能重载

对象生命周期结束时,C++编译系统系统自动调用析构函数。

class Date
{
public:
	~Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

private:
	int _year;
	int _month;
	int _day;

};

对于类的成员是自定义类型的,析构函数不做处理,但是如果是自定义类型,就回去调用它的析构函数

我们不定义,编译器会默认生成一个,里边的操作同5

三、拷贝构造函数

说明:

用 该类 创建的对象 去给新对象赋值的过程 叫做拷贝构造(一个创建成功,一个未创建),切记不是赋值重载,赋值重载的前提是两个对象都创建完成

特性:

拷贝构造的书写形式:函数名与类名相同,没有返回值,参数为const +类+&+对象(已经创建的对象)
为什么要传引用?而不是直接类 类型的参数?
原因是因为在调用拷贝构造时,需要先传参,而C++在类 类型对象传参时会调用拷贝构造, 而拷贝构造再一次传参仍调用拷贝构造,这样会导致无穷递归下去
在这里插入图片描述
在这里插入图片描述
而如果传引用就不需要开辟新的对象,就免去了传参时去调用拷贝构造,在确保不会改变此对象时,最好加上const保护一下
由此不难看出,下次我们无论写函数传参还是函数返回值时,能用引用就用引用,这样程序运行效率更高更快(避免拷贝临时变量等操作)

拷贝构造也属于构造,若存在拷贝构造且不存在我们自己定义的构造,那么编译器就不会生成默认构造函数
在这里插入图片描述

在这里插入图片描述
你或许看出了,这没写拷贝构造,只写了一个构造,但是依旧完成了操作,所以拷贝构造不写,编译器会默认生成一份仅完成浅拷贝(逐字节拷贝,若是地址,也原样拷贝)
两个地址一样
两个地址一样,销毁时就会导致一个内存被释放两次,第一次释放没事,考虑极端情况,若第一次刚刚释放完,就被分配到其他位置使用,那么此时该地址处的内容已经不属于你,不能第二次释放,此时就需要我们手动写一个拷贝函数(俗称深拷贝)

	Stack(const Stack& st)
	{
		int* tmp = (int*)malloc(sizeof(int) * st.capacity);
		if (tmp == nullptr)
		{
			return;
		}
		memcpy(tmp, st.a, sizeof(int) * st.top);

		a = tmp;
		top = st.top;
		capacity = st.capacity;
	}

四、赋值重载

前言:为了使代码规范,C++规定,可以使用 operator加上运算符 做函数名,和函数一样

说明:

内置类型可以使用等号运算符,那么如果我们想让自定义类型也使用等号运算符呢?这时候就需要我们把 = 的含义重载一下

特性:

参数类型:const T&,返回值类型:T&,函数名operator=
参数类型,上边提到过,便于提高运行效率;而返回值用引用其一效率高,其二可以接连赋值

class A
{
public:
	A(int a1 = 1, int a2 = 1)
	{
		_a1 = a1;
		_a2 = a2;
	}
	
	//1.operator 需要两个参数,在类里边,
	//默认有一个this指针充当第一个参数
	//2.有返回值的目的是为了能接连赋值,
	//否则函数没有返回值 调用时就是  a3 = a1.operator=(a2)
	//总不能把void 赋值给a3吧
	A& operator=(const A& a)
	//A operator=(const A& a)
	{
		_a1 = a._a1;
		_a2 = a._a2;

		return *this;
	}
private:
	int _a1;
	int _a2;
};

int main()
{
	A a1(6, 6);
	A a2,a3;

	a1.operator=(a2); //等价于  a2=a1 在c++中一般用后者
	a3 = a2 = a1;  //a3 = a1.operator=(a2)
	
	return 0;
}

赋值重载函数,编译器会在我们没有写的情况下,默认生成一个赋值重载函数,仅仅完成浅拷贝,与拷贝构造一样

赋值运算符只能重载成类的成员函数,不能定义在类外
因为在调用时有两个函数(一个我们定义在类外部的,一个是类默认生成的),会产生调用冲突

编译器会灵活看待等号,对于内置类型,就不会去调用函数重载,对于自定义类型,则会去调用函数重载

五、取地址重载&const取地址重载

说明:

取地址重载可以获取对象的地址
const取地址重载获取const对象的地址

class Date
{ 
public :
	Date* operator&()
	{
		return this ;
	}
 
	 const Date* operator&()
	 {
	 	return this ;
	 }
private :
	 int _year ; 
	 int _month ; 
	 int _day ; 
};

特性:

不写时 编译器会自动生成

这两个函数比较单纯,取地址而已,故使用默认生成的就行

总结

1. 构造与拷贝构造,99%的情况下都需要自己手搓一个,因为我们不想要随机值初始化对象
2. 拷贝构造与赋值重载,如果是浅拷贝不涉及动态内存的可以用 不写,用默认的,如果涉及malloc 等需要我们写
3. 取地址重载与const取地址重载,不需要我们写,直接用就行

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值