构造函数与析构函数详解

一、构造函数

1.什么是构造函数

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

2.特征

  1. 函数名与类名相同。
  2. 无返回值。(void 也不行)
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
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 d1(2023, 8, 12);
	d1.Print();

	
}

除了上面,也可以用多种构造函数,来完成初始化

class Date
{
public:
	//构造函数
	Date(int year ,int month , int day )
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//无参构造函数
	Date()
	{
		_year = 2023;
		_month = 4;
		_day = 17;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

int main()
{
	Date d1(2023, 8, 12);
	d1.Print();

	Date d2;
	d2.Print();
}

构造函数与析构函数详解_第1张图片

但是当这样写的时候,就会出现问题

class Date
{
public:
	//全缺省构造函数
	Date(int year = 1 ,int month  = 1, int day = 1 )
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//无参构造函数
	Date()
	{
		_year = 2023;
		_month = 4;
		_day = 17;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

int main()
{
	Date d1(2023, 8, 12);
	d1.Print();

	Date d2;
	d2.Print();

	
}

在这里插入图片描述
错误原因:对于不带参数的对象,既可以调用全缺省构造,也可以调用无参构造,但是编译器会不知道调用哪一个。

3.默认构造函数

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

1、无参构造(没有形参的构造函数)称之为默认构造函数

2、全缺省构造(形参都有缺省值)也称之为默认构造函数

3、编译器自动生成的默认构造函数

对于编译器自己生成的,该类中的成员变量会被初始化为随机值

class Date
{
public:
	全缺省构造函数
	//Date(int year = 1 ,int month  = 1, int day = 1 )
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}

	无参构造函数
	//Date()
	//{
	//	_year = 2023;
	//	_month = 4;
	//	_day = 17;
	//}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

int main()
{
	/*Date d1(2023, 8, 12);
	d1.Print();*/

	Date d2;
	d2.Print();

	return 0;
}

构造函数与析构函数详解_第2张图片

关于编译器生成的默认成员函数,很多人会有疑惑:不实现构造函数的情况下,编译器会
生成默认的构造函数。但是看起来默认构造函数又没什么用?
对象调用了编译器生成的默认构造函数,但是对象_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
{
public:
	全缺省构造函数
	//Date(int year = 1 ,int month  = 1, int day = 1 )
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}

	无参构造函数
	//Date()
	//{
	//	_year = 2023;
	//	_month = 4;
	//	_day = 17;
	//}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

private:
	//内置类型
	int _year;
	int _month;
	int _day;

	//自定义类型
	Time _t;
};

int main()
{
	/*Date d1(2023, 8, 12);
	d1.Print();*/

	Date d2;
	d2.Print();

	return 0;
}

构造函数与析构函数详解_第3张图片
说明:_year,_month,_day都是随机值,而Time _t这个变量是class Time自定义类型,编译器会走到Time类中,调用该类的构造函数。

typedef int STDateType;
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		cout << "Stack()" << endl;
		_array = (STDateType*)malloc(sizeof(STDateType) * capacity);
		if (_array == nullptr)
		{
			perror("malloc fail");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}

	void Push(STDateType x)
	{
		//CheckCapacity()
		_array[_size++] = x;
	}

	//析构函数
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_capacity = _size = 0;
	}
private:
	STDateType* _array;
	int _capacity;
	int _size;
};

class MyQueue
{
	Stack _pushST;
	Stack _popST;

};

int main()
{
	MyQueue q;
	return 0;
}

构造函数与析构函数详解_第4张图片

对于MyQueue来说,成员变量都为自定义类型,编译时会去调用Stack中的构造函数

二、析构函数

1.定义

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

2.特性

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
typedef int STDateType;
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		cout << "Stack()" << endl;
		_array = (STDateType*)malloc(sizeof(STDateType) * capacity);
		if (_array == nullptr)
		{
			perror("malloc fail");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}

	void Push(STDateType x)
	{
		//CheckCapacity()
		_array[_size++] = x;
	}

	//析构函数
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_array);
		_array = nullptr;
		_capacity = _size = 0;
	}
private:
	STDateType* _array;
	int _capacity;
	int _size;
};

class MyQueue
{
	Stack _pushST;
	Stack _popST;

};

int main()
{
	Stack s;
	s.Push(1);

	return 0;
}

析构函数的调用是在执行return 0后,函数即将销毁时自动调用它,然后堆区空间就会被释放,且其他变量清零。

4.默认析构类型

默认析构函数与默认构造函数同理,都是我们不生成时,编译器自动生成一个析构函数,但编译器生成的也只能处理一些简单类型的成员变量,例如日期类:

class Date
{
public:
	//全缺省构造函数
	Date(int year = 1 ,int month  = 1, int day = 1 )
	{
		_year = year;
		_month = month;
		_day = day;
	}

	无参构造函数
	//Date()
	//{
	//	_year = 2023;
	//	_month = 4;
	//	_day = 17;
	//}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

private:
	//内置类型
	int _year;
	int _month;
	int _day;

	//自定义类型
	Time _t;
};

int main()
{
	Date d1(2023, 8, 13);
	return 0;
}

对于复杂类型的成员变量,编译器自动生成的析构函数并不能完成最后的清理工作,比如:对于堆区空间的生成…所以还需要自己去写析构函数

你可能感兴趣的:(c++,开发语言,c++)