C++总结笔记(五)——构造函数和析构函数

文章目录

  • 前言
  • 一、基本概念
    • 1 构造函数
    • 2 析构函数
  • 二、示例
    • 1. 构造函数和析构函数的简单使用
    • 2. 拷贝构造函数的调用
    • 3. 浅拷贝和深拷贝


前言

本文讲述了构造函数和析构函数的概念以及对应的示例,以便加深理解。


一、基本概念

1 构造函数

构造函数用于初始化类的对象,可以由程序员自己定义,也可以由编译器定义(构造函数内为空)。
其特点:
1.没有返回类型。
2.函数名和类名相同。
3.可以有参数,也可以没有。
4.可以重载。
5.程序会自动调用。
按照参数分类
1.无参构造函数
2.有参构造函数(包括拷贝构造函数)
3种构造方法
1.括号法
2.显示法
3.隐式转换法
调用规则
1.编译器会给类添加至少三个构造函数:1,默认构造函数;2,析构函数(空);3,拷贝构造函数(值拷贝):如果不写拷贝构造,编译器会自动生成一个拷贝构造函数,Name = c.Name;。
2.如果自己写了有参构造函数,编译器不会再提供默认构造函数,但还是会提供拷贝构造函数。
3.如果自己写了拷贝构造函数,编译器其他两种构造函数都不会再提供。

2 析构函数

析构函数用于销毁之前声明的类对象,系统自动调用,用~+类名声明。
1.析构函数不可以有参数。
2.析构函数无法重载。

二、示例

1. 构造函数和析构函数的简单使用

class Cat
{
public:
	Cat()
	{
		cout << "喵是无参构造函数" << endl;
	}

	Cat(string name)
	{
		Name = name;
		cout << "喵是有参构造函数" << endl;
	}
    //用于拷贝c的属性值,用常量引用的方式进行
	Cat(const Cat &c)
	{
		Name = c.Name;
		cout<< "喵是拷贝构造函数" << endl;
	}

	~Cat()
	{
		cout << "喵是析构函数" << endl;
	}

	string Name;//咪咪名字
};

void FindName()
{
	//括号法
	Cat cat1;//用默认构造函数时,不能加括号,否则编译器会当作函数声明。
	Cat cat2(cat1);//拷贝构造函数调用
	Cat cat3("小300");//有参构造函数调用。
	Cat cat4(cat3);//拷贝构造函数调用
	
	cout << "第一个猫的名字是:" << cat1.Name << endl;
	cout << "第二个猫的名字是:" << cat2.Name << endl;
	cout << "第三个猫的名字是:" << cat3.Name << endl;
	cout << "第四个猫的名字是:" << cat4.Name << endl;

	//显示法
	Cat cat5;//默认构造函数
	Cat cat6 = Cat("三号楼");//有参构造函数调用。
	Cat cat7 = Cat(cat6);//拷贝构造函数调用
	Cat("蹭铁棍");//匿名对象,会直接调用构造函数和析构函数,再去执行后面的内容。
	//Cat(cat7);不要匿名初始化拷贝构造函数
	cout << "第五个猫的名字是:" << cat5.Name << endl;
	cout << "第六个猫的名字是:" << cat6.Name << endl;
	cout << "第七个猫的名字是:" << cat7.Name << endl;

	//隐式调用
	string name8 = "来两根";
	Cat cat8 = name8;
	cout << "第八个猫的名字是:" << cat8.Name << endl;
}

int main()
{
	FindName();
}
喵是拷贝构造函数
喵是普通有参构造函数
喵是拷贝构造函数
第一个猫的名字是:
第二个猫的名字是:
第三个猫的名字是:小300
第四个猫的名字是:小300
喵是无参构造函数
喵是普通有参构造函数
喵是拷贝构造函数
喵是普通有参构造函数
喵是析构函数
第五个猫的名字是:
第六个猫的名字是:三号楼
第七个猫的名字是:三号楼
喵是普通有参构造函数
第八个猫的名字是:来两根
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数

2. 拷贝构造函数的调用

void eat1(Cat cat)
{
	cout << cat.Name << "吃猫粮" << endl;
}

Cat eat2()
{
	Cat cat("炸糊的栗子");
	cout << cat.Name << "吃骨头" << endl;
	return cat;
}
void FindName()
{
	//使用一个已经创建的对象来初始化新的对象
	Cat cat1("小300");//有参构造函数调用。
	Cat cat2(cat1);//拷贝构造函数调用
	
	cout << "第一个猫的名字是:" << cat1.Name << endl;
	cout << "第二个猫的名字是:" << cat2.Name << endl;

	//值传递传值      
	Cat cat3("烤糊的栗子");
	eat1(cat3);
	cout << "第三个猫的名字是:" << cat3.Name << endl;

	//值方式返回局部对象
	Cat cat4 = eat2();
	cout << "第四个猫的名字是:" << cat4.Name << endl;
}
喵是普通有参构造函数
喵是拷贝构造函数
第一个猫的名字是:小300
第二个猫的名字是:小300
喵是普通有参构造函数
喵是拷贝构造函数
烤糊的栗子吃猫粮
喵是析构函数
第三个猫的名字是:烤糊的栗子
喵是普通有参构造函数
炸糊的栗子吃骨头
喵是拷贝构造函数
喵是析构函数
第四个猫的名字是:炸糊的栗子
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数

3. 浅拷贝和深拷贝

深拷贝:在堆区开辟空间,完成拷贝。
浅拷贝:简单赋值拷贝的方式就属于浅拷贝,比如默认的拷贝构造函数。

class Cat
{
public:
	Cat()
	{
		cout << "喵是无参构造函数" << endl;
	}

	//Cat(string name)
	//{
	//	Name = name;
	//	cout << "喵是普通有参构造函数" << endl;
	//}

	Cat(string name, int age)
	{
		Name = name;
		Age = new int(age);
		cout << "喵是普通有参构造函数" << endl;
	}

	Cat(const Cat &c)
	{
		Name = c.Name;
		//深拷贝,用new将传入Age的地址解引用然后在堆区重新创建一个空间,与cat3所指向的新内存空间就不一样了,不会发生析构函数重复释放报错的问题。
		Age = new int(*c.Age);

		cout<< "喵是拷贝构造函数" << endl;
	}

	~Cat()
	{
		if (Age != NULL)
		{
			delete Age;
			Age = NULL;
		}
		cout << "喵是析构函数" << endl;
	}

	string Name;//咪咪名字
	int *Age;//咪咪年龄
};

void FindName()
{
	浅拷贝,仅发生值传递
	//Cat cat1("小300");
	//Cat cat2(cat1);
	//
	//cout << "第一个猫的名字是:" << cat1.Name << endl;
	//cout << "第二个猫的名字是:" << cat2.Name << endl;

	//深拷贝,用new在内存中开辟新空间
	Cat cat3("小300",2);
	Cat cat4(cat3);

	cout << "第三个猫的名字是:" << cat3.Name << endl;
	cout << "第三个猫的年龄是:" << *cat3.Age << endl;
	cout << "第四个猫的名字是:" << cat4.Name << endl;
	cout << "第四个猫的年龄是:" << *cat4.Age << endl;
}

int main()
{
	FindName();
}
喵是普通有参构造函数
喵是拷贝构造函数
第三个猫的名字是:小300
第三个猫的年龄是:2
第四个猫的名字是:小300
第四个猫的年龄是:2
喵是析构函数
喵是析构函数

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