C++相关概念和易错语法(4)(构造函数、析构函数)

一、构造函数

1.实现的功能:实例化对象的时候默认自动调用,相当于初始化。

19093f10ee284c939e94f3204f309529.png

条件:在书写时要满足构造函数的规范(函数名 == 类名,不写返回值,也没有返回值),可以用inline来修饰。

2.自定义构造函数

在自定义构造函数的时候,要清楚默认调用的构造函数是没有传参的,即c1.C(),如果有自定义构造函数,那么下面的这种情况要报错:

1de11d56bd7d453eb99ad3437a8c9728.png

构造函数也支持函数重载,我们可以进一步验证:

8db8d15234fa405288413c28867c15c2.png

这里就能很明显的看到,在默认调用的情况下,只会以c1.C()这种形式去调用(注意:c1.C()这种写法是错误的,这里只是为了形象表示,下同)。

因此,在我们平时自定义构造函数的时候,最好使用全缺省参数,这样的话在我们有特殊初始化需求的时候可以选择自己传参,在其余情况又能默认初始化,这样会很方便。


#include <iostream>
using namespace std;

class C
{
public:
	C(int a, int b, int c)
	{
		_a = a, _b = b, _c = c;
	}

	C(int a = 1)
	{
		_a = _b = _c = a;
	}

private:
	int _a;
	int _b;
	int _c;
};

int main()
{
	C c1;

	C c2(4, 5, 6);

	return 0;
}

注意构造函数是在定义的时候就调用的,格式要严格遵守

40ef5f0f604141bab5abd99028f91e05.png

3.自动生成的构造函数条件

只有在没有自定义构造函数的情况下才会自动生成构造函数。

如果自定义了一个有参数的构造函数,且没有在定义的时候使用,C++也不会自动生成,此时会报错。

1de11d56bd7d453eb99ad3437a8c9728.png

所以要么别自定义构造函数,要么就要定义一个无参或者全缺省的构造函数。如果一定要定义一个有参的构造函数,那么实例化对象时,一定要在定义时调用构造函数,如 C c1(1, 2, 3);

4.自动生成的构造函数的初始化规则

先看一段代码,尝试解释:


class C1
{
public:
	C1(int a = 1, int b = 1)
	{
		_a = a, _b = b;
	}
private:
	int _a;
	int _b;
};

class C2
{
private:
	int _x;
	int _y;
	C1 _z;
};


int main()
{
	C2 c2;

	return 0;
}

c2的各个成员变量的初始化值是:

36c6f2d806d74d88bf1977fab223b781.png

我们发现,_x和_y并没有初始化,而_a和_b初始化了,如何解释?

首先需要清楚C/C++内置类型(基本类型)和自定义类型:

内置类型:void、char、short、int、long、float、double、void*、int*等

自定义类型:struct、class、enum等

自动生辰的构造函数初始化成员变量,针对内置类型和自定义类型有不同的初始化方式。

对于内置类型:不进行初始化;

对于自定义类型:调用这些自定义类型的无参(全缺省)构造函数。

对上面的现象分析如下:

d25669fc89ab48b3a48c42396060e5d2.png

尝试解释下面的初始化现象:


class C1
{
public:
	C1(int a = 1, int b = 1)
	{
		_a = a, _b = b;
	}
private:
	int _a;
	int _b;
};

class C2
{
public:
	C2()
	{
		_x = _y = 2;
	}
private:
	int _x;
	int _y;
	C1 _z;
};


class C3
{
private:
	int _p;
	int _q;
	C2 _r;
};


int main()
{
	C3 c3;

	return 0;
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

结果是:

cc3798d7ca194084b6ee5b3210a49e66.png

解释:c3没有自定义构造函数,所以自动生成构造函数。_p和_q都是内置类型所以不会初始化,_r是自定义类型,所以调用_r的自定义构造函数。

_r有自定义构造函数,将_x和_y都初始化为2,_z是自定义类型,所以调用_z的自定义构造函数。

_z有自定义构造函数,将_a和_b都初始化为2。

如果成员变量中自定义类型和内置类型同时存在,在少数编译器中,还是会初始化内置类型的。但显然,刚刚演示的编译器就不是这样的。这点也不需要纠结

二、析构函数

实现的功能:在对象生命周期结束后自动free掉堆区开辟的空间,防止内存泄漏。

56e5a4813c2044a981b0ea458fb70897.png

条件:函数名 == ~类名,没有参数,没有返回值,不写返回值。

因为析构函数在对象的生命周期结束后会自动调用,因此它可以很好的解决内存泄漏的问题。

需要注意的是,析构函数不能带有参数,包括全缺省,所以也不需要考虑传参的各种情况。

9fbbf9c2823044fa9c10eb92975dde69.png

析构函数还可以显式调用,如c.~c()

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值