C++类(3)

1.如果一个类什么成员都没有,简称空类

但是空类真的什么都没有吗?

并不是,任何类什么都不写,编译器会自动生成以下6个默认成员函数

1.构造函数 

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void print(void)
		{
			cout << _year << _month << _day << endl;
		}
private:
	int _year;
	int _month;
	int _day;
};

int main(void)
{
	Date d1;
	d1.Init(2005, 4, 14);
	d1.print();
	return 0;
}

对于Date类,可以通过Init共有的方法给对象设置信息,但是每次创建新的对象,都要取调用Init函数,好麻烦啊!那能不能在创建对象的时候就把信息设置进去呢?

这个时候就可以用构造函数了

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

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

int main(void)
{
	Date d1(2005, 4, 14);//调用带参数的构造函数
	Date d2;//调用无参构造函数
	Date d3();//编译器会报错
	//如果通过无参构造函数创建对象的时,对象后面不用跟括号,否则就成了函数声明,比如d3
	d1.print();
	return 0;
}

这个地方Date d1(2005,4,14)不会被当作函数声明是因为,函数声明里面是类型

但是Date d3()编译器就无法判断了!

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

其特征如下

1.函数名与类名相同(都是Date)

2.无返回值(不能写返回值,包括void也不可以)

3.对象实例化时编译器自动调用对应的构造函数

4.构造函数可以重载

那么如果我没有显示定义构造函数,则C++编译器会自动生成一个无参的默认的构造函数,一旦用户显示定义编译器将不再生成

这也就是为啥上面两个例子,不管我写不写构造函数

Date d1;
Date d2;

这种都可以编译通过

本质上编译器帮你写了一个

Date()
{

}

因此你会发现如果我这

因此你发现如果我这样写编译器就会报错

本质上是因为我自己写了显示定义函数,导致原本的无参的默认的构造函数消失了! 

但是你会发现一件很神奇的事就是,哪怕有这个默认的无参构造函数,但是我依然打印出来的是一个随机值,那么这个默认的无参构造函数的意义在哪呢?

 

1.一般情况下,有内置成员变量,就需要自己写构造函数,不能用编译器具体生成的

2.全部都是自定义类型成员,可以考虑让编译器自己生成

此外,这个地方是随机值的原因是没有初始化

(1).内置类型,基本类型,语言本身定义的基础类型,

   如int /char/double/指针等 

(2).自定义,struct /class等等定义的类型

我们对于内置类型等等(1)编译器不做处理,自定义类型(2)会去调他的默认构造

当然有些编译器也会对内置类型等等(1)处理,但那是个性化行为,并不是所有编译器都这么做!

(对于析构函数同样适用)

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

就像下面这样

class Date
{
public:
	void print(void)
		{
			cout << _year << _month << _day << endl;
		}
private:
	//内置类型  C++11支持 这里不是初始化只是声明 不开辟空间
	//这里给的是默认的缺省值,给编译器生成默认构造函数用
	int _year=2005;
	int _month=4;
	int _day=14;
};

int main(void)
{
	Date d1;
	d1.print();
	return 0;
}

但是如果自己写了显示定义函数,那个缺省值就没用了!

有了缺省值,我们传参传几个都可以!同样这种由于构造函数支持重载,也需要和重载函数一样避免歧义!

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

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

2.析构函数

构造函数可以帮助我们完成初始化,那么有没有什么函数可以帮助我们完成销毁呢?

答案就是析构函数

class stack
{
public:
	stack(size_t capacity = 3)//构造函数
	{
		_arry = (Datetype*)malloc(sizeof(Datetype) * capacity);
		if (_arry == NULL)
		{
			perror("malloc fail");
		}
		_capacity = capacity;
		_size = 0;
	}
	void push(Datetype data)
	{
		//Checkcapacity()这个地方还有一个检查容量的函数暂时省略不写
		_arry[_size] = data;
		_size++;
	}
	
	~stack()//析构函数
	{
		if (_arry)
		{
			free(_arry);
			_arry = 0;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	Datetype* _arry;
	int _capacity;
	int _size;
};

int main(void)
{

	stack d1(66);
	d1.push(1);
	d1.push(11);
	return 0;
}

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

1.析构函数名是在类名前面加一个~

2.无参数无返回值(无返回值也不能写void)

3.一个函数只能有一个析构函数,若未显示定义,系统会自动生成默认的析构函数。

注意:析构函数不能重载

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

比如上面那个例子就是在return 0;前调用析构函数!

我们来看下面这个例子

class Time
{
public:
	~Time()
	{
		cout << "~Time()" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class date
{

private:
	int _year=2005;
	int _month=4;
	int _day=14;
	Time arry;
};
int main(void)
{
	date a;
	return 0;
}

为啥我调用的是date打印的却是Time的析构函数呢?

首先date里面的三个变量_year,_month,_day都是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;

但是arry是Time类是自定义类型,date销毁的时候,会将date里面的四个变量都销毁,所以销毁arry要调用Time的析构函数,

但是main函数里面不能直接调用Time的析构函数,实际要释放的是Date类的对象,所以编译器会调用date类的析构函数,

但是date没有提供显示的析构函数,因此编译器会给date生成一个默认的析构函数,目的是在其内部调用time类的析构函数,

即当date类被销毁时,要保证其内部每个自定义对像都可以正确销毁

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

那么在最后总结一下,什么时候要自己写构造函数和析构函数

构造函数:

1.一般情况,构造函数都需要我们自己写
不用写的情况:

a.内置类型成员全都有缺省值,且初始化符合我们的需求

b.全是自定义类型的构造,且这些类型都定义默认构造

析构函数:

1.一般情况,有动态申请资源,就需要显示写析构函数释放找资源

2.没有动态申请的资源,不需要写析构

3.需要释放资源的成员都是自定义类型,不需要写析构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值