c++学习——构造函数和析构函数

构造函数和析构函数

    • **简要概述**
    • **构造函数和析构函数的简单调用**
    • **构造函数和析构函数能够函数重载**
    • **默认的构造函数和析构函数**
    • **拷贝构造**
    • **构造函数的分类和调用**
    • **匿名对象**
    • **拷贝构造函数的调用时机**
    • **构造函数的调用规则**
    • **多个对象的构造函数和析构函数**
    • **深浅拷贝**
    • **补充:初始化列表**

简要概述

当对象产生时,必须初始化成员变量,当对象销毁前,必须清理对象.
初始化用构造函数,清理用析构函数,这两个函数是编译器调用 初始化的作用和析构函数的作用

构造函数点和析构函数的注意:
构造函数和析构函数的权限必须是公有的
构造函数可以重载
构造函数没有返回值,不能用void,构造函数可以有参数,析构函数没有返回值,不能用void,没有参数
有对象产生必然会调用构造函数,有对象销毁必然会调用析构函数。
有多少个对象产生就会调用多少次构造函数,
有多少个对象销毁就会调用多少次析构函数

构造函数和析构函数的简单调用

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	//构造函数的作用初始化成员变量  是编译器去调用的
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}
	//析构函数,在对象销毁前编译器调用析构函数
	~Maker()
	{
		cout << "析构函数" << endl;
	}
public:
	int a;
};

void test01()
{
	//实例化对象,内部做了两件事 
	//1、分配空间
	//2、调用构造函数进行初始化
	Maker m;//栈区
	int b = m.a;
	cout << b << endl;
}

int main()
{
	test01();
	Maker m2;
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述
这里由于system(“pause”);暂停了,还没有调用析构函数
在这里插入图片描述
暂停结束后就调用了析构函数

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	//构造函数的作用初始化成员变量  是编译器去调用的
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}
	//析构函数,在对象销毁前编译器调用析构函数
	~Maker()
	{
		cout << "析构函数" << endl;
	}
public:
	int a;
};

void test01()
{
	//实例化对象,内部做了两件事 
	//1、分配空间
	//2、调用构造函数进行初始化
	Maker m;//栈区
	int b = m.a;
	cout << b << endl;
}

//析构函数的作用
class Maker2
{
public:
	//有参构造
	Maker2(const char* name,int age)
	{
		cout << "有参构造" << endl;
		//从堆区空间申请
		pName = (char *)malloc(strlen(name) + 1);
		strcpy(pName, name);
		mAge = age;
	}

	void printMaker2()
	{
		cout << "name:" << pName << " age:" << mAge << endl;
	}

	~Maker2()
	{
		cout << "析构函数001" << endl;
		//释放堆区空间
		if (pName!=NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
private:
	char* pName;
	int mAge;
};

void test02()
{
	Maker2 m2("贝吉塔", 18);
	m2.printMaker2();
}

int main()
{
	//test01();
	test02();
	Maker m2;
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

构造函数和析构函数能够函数重载

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	//构造函数的作用初始化成员变量  是编译器去调用的
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}
	//析构函数,在对象销毁前编译器调用析构函数
	~Maker()
	{
		cout << "析构函数" << endl;
	}
public:
	int a;
};

void test01()
{
	//实例化对象,内部做了两件事 
	//1、分配空间
	//2、调用构造函数进行初始化
	Maker m;//栈区
	int b = m.a;
	cout << b << endl;
}

//析构函数的作用
class Maker2
{
public:
	//有参构造
	Maker2(const char* name,int age)
	{
		cout << "有参构造" << endl;
		//从堆区空间申请
		pName = (char *)malloc(strlen(name) + 1);
		strcpy(pName, name);
		mAge = age;
	}

	void printMaker2()
	{
		cout << "name:" << pName << " age:" << mAge << endl;
	}

	~Maker2()
	{
		cout << "析构函数001" << endl;
		//释放堆区空间
		if (pName!=NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
private:
	char* pName;
	int mAge;
};

class Maker3
{
public://构造函数和析构函数必须是公有权限
	//构造函数可以重载
	Maker3()//无参构造函数
	{
		cout << "Maker3的无参构造" << endl;
	}
	Maker3(int a)//有参构造函数
	{
		cout << "Maker3的有参构造" << endl;
	}
	~Maker3()
	{
		cout << "析构函数" << endl;
	}
};

void test02()
{
	Maker2 m2("贝吉塔", 18);
	m2.printMaker2();
}

void test03()
{
	Maker3 m;//当构造函数私有时,实例化不了对象
	//有对象产生必然会调用构造函数,有对象销毁析构函数
	//有多少个对象产生就会调用多少次构造函数
	//有多少个对象销毁就会调用多少次析构函数
	Maker3 m2(10);
}

int main()
{
	//test01();
	//test02();
	test03();
	//Maker m2;
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

默认的构造函数和析构函数

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	//Maker()//默认的构造函数,函数体是空的
	//{

	//}
	//~Maker()//默认的析构函数,函数体是空的
	//{

	//}
	//编译器默认提供默认的构造函数和析构函数
	void printfMaker()
	{
		a = 100;
		cout << "a=" << a << endl;
	}
private:
	int a;
};
void test01()
{
	Maker m;
	m.printfMaker();
}
int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

拷贝构造

拷贝构造必须要引用
c++学习——构造函数和析构函数_第1张图片

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	//拷贝构造函数
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
		a = m.a;
	}
	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};

void test01()
{
	Maker m1;
	m1.printMaker();
	//用一个已有的对象去初始化另一个对象
	Maker m2(m1);
	m2.printMaker();
}

class Maker2
{
public:
	Maker2()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}

	//编译器提供了默认的拷贝构造函数
	//Maker2(const Maker2 &m)
	//{
	//	//默认拷贝构造函数进行了成员变量的简单拷贝
	//	//默认拷贝构造函数进行了成员变量的简单拷贝
	//	a = m.a;
	//}

	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};

//拷贝构造函数中形参要用引用
void test02()
{
	Maker2 m1;
	m1.printMaker();

	Maker2 m2(m1);
	m2.printMaker();
}

class Maker3
{
public:
	Maker3(int Ma)
	{
		cout << "有参构造函数" << endl;
		ma = Ma;
	}
	Maker3(const Maker3 &m)
	{
		cout << "拷贝构造函数" << endl;
	}
private:
	int ma;
};

void test03()
{
	Maker3 m1(10);//调用有参构造
	
	Maker3 m2(m1);//调用拷贝构造

	Maker3 m3 = m1;//调用拷贝构造 编译器会优化为Maker3 m3(m1);

	//如果拷贝构造函数中的形参不是引用

	/*Maker3(const Maker3 m)  const Maker3 m=m1;     编译器:const Maker3 m(m1)
	{
		cout << "拷贝构造函数" << endl;
	}

	1、Maker3 m2(m1);
	2、const Maker3 m=m1;
	3、const Maker3 m(m1);
	……死循环
	*/
	
}

int main()
{
	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}

构造函数的分类和调用

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

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

	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}

	//拷贝构造函数
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
	}

	//默认的赋值函数
};

void test01()
{
	Maker m;//调用无参构造函数
	Maker m1(10);//调用有参构造
	Maker m2(m1);//调用拷贝构造



	//不常用的
	Maker m3 = m2;//调用拷贝构造
	Maker m4 = Maker(10);//调用的是有参构造函数
	cout << "-------------------" << endl;
	Maker m5 = 10;//编译器:Maker m5=Maker(10);  有参构造函数

	Maker m6;
	m6 = m5;//赋值操作
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——构造函数和析构函数_第2张图片

匿名对象

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

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

	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}

	//拷贝构造函数
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
	}
	~Maker()
	{
		cout << "析构函数" << endl;
	}
	//默认的赋值函数
};

void test01()
{
	//Maker();//匿名对象的生命周期在当前行
	Maker(10);//这也是匿名对象
	//Maker m1(10);
	Maker m1 = Maker();//这不是匿名对象  生命周期在函数体结束
	cout << "test01函数结束" << endl;
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

拷贝构造函数的调用时机

test03在Debug下的调用 会调用拷贝构造
c++学习——构造函数和析构函数_第3张图片
test03在vs下的 Realease下的调用,不会调用拷贝函数
这种模式下编译器会认为m和m1是同一个对象
qt也不调用
c++学习——构造函数和析构函数_第4张图片

构造函数的调用规则

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}

	//拷贝构造函数
	//Maker(const Maker &m)
	//{
	//	cout << "拷贝构造函数" << endl;
	//}
};

//1、如果程序员提供了有参构造函数,那么编译器不会提供默认的构造函数,但是会提供默认的拷贝构造函数
void test01()
{
	//Maker m;   err
	Maker m(10);//调用有参构造
	Maker m2(m);//调用了默认的拷贝构造
}

//2、如果程序员提供了拷贝构造函数,那么编译器不会提供默认的构造函数和拷贝构造函数
void test02()
{
	//Maker m; err
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

多个对象的构造函数和析构函数

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class BMW
{
public:
	BMW()
	{
		cout << "BMW构造" << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick()
	{
		cout << "Buick构造" << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	Maker()
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	BMW bmw;//成员对象
	Buick bui;//成员对象
};
//1、如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数
//析构函数的调用顺序反之
//2、成员对象的构造函数调用和定义顺序一样
//3、注意,如果有成员对象那么实例化对象时,必须保证成员对象的构造和析构能被调用
void test01()
{
	Maker m;
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——构造函数和析构函数_第5张图片
这里我在第一个类传参数,下面进行调用需要在构造函数中加:

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW构造 " << a << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick()
	{
		cout << "Buick构造" << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	Maker():bmw(10)
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	BMW bmw;//成员对象
	Buick bui;//成员对象
};
//1、如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数
//析构函数的调用顺序反之
//2、成员对象的构造函数调用和定义顺序一样
//3、注意,如果有成员对象那么实例化对象时,必须保证成员对象的构造和析构能被调用
void test01()
{
	Maker m;
}

//初始化列表时调用成员对象的指定构造函数
void test02()
{
	Maker m;
}
int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——构造函数和析构函数_第6张图片
下一段代码void test02()中我改成了有参 因此就要这样调用

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW构造 " << a << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick()
	{
		cout << "Buick构造" << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	//初始化列表
	//注意:初始化列表只能写在构造函数里面
	Maker(int a):bmw(a)
	{
		cout << "Maker构造" << endl;
	}
	//注意2:如果使用了初始化列表,那么所以的构造函数都要写初始化里列表
	Maker(const Maker &m):bmw(40)//初始化
	{

	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	BMW bmw;//成员对象
	Buick bui;//成员对象
};
//1、如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数
//析构函数的调用顺序反之
//2、成员对象的构造函数调用和定义顺序一样
//3、注意,如果有成员对象那么实例化对象时,必须保证成员对象的构造和析构能被调用
void test01()
{
	//Maker m;
}

//初始化列表时调用成员对象的指定构造函数
void test02()
{
	Maker m(20);
}
int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW构造 " << a << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick(int b,int c)
	{
		cout << "Buick构造 " << b << " " << c << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	//初始化列表
	//注意:初始化列表只能写在构造函数里面
	//如果有多个对象需要指定调用某个构造函数,用逗号隔开
	//Maker(int a):bmw(a),bui(10,20)
	Maker(int a,int b,int c):bmw(a),bui(b,c)
	{
		cout << "Maker构造" << endl;
	}
	//注意2:如果使用了初始化列表,那么所以的构造函数都要写初始化里列表
	//初始化
	Maker(const Maker &m):bmw(40),bui(10,20)
	{

	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	BMW bmw;//成员对象
	Buick bui;//成员对象
};
//1、如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数
//析构函数的调用顺序反之
//2、成员对象的构造函数调用和定义顺序一样
//3、注意,如果有成员对象那么实例化对象时,必须保证成员对象的构造和析构能被调用
void test01()
{
	//Maker m;
}

//初始化列表时调用成员对象的指定构造函数
void test02()
{
	//Maker m(20);
	Maker m(20,10,20);
}
int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——构造函数和析构函数_第7张图片

深浅拷贝

浅拷贝案例及问题:

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker(int id, int age)
	{
		mId = id;
		mAge = age;
	}
public:
	int mId;
	int mAge;
};

class Student
{
public:
	Student(const char *name, int Age)
	{
		pName = (char*)malloc(strlen(name));
		strcpy(pName, name);
		age = Age;
	}
	//写析构函数释放
	~Student()
	{
		cout << "析构函数" << endl;
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
public:
	char *pName;
	int age;
};

void test01()
{
	Maker m1(1, 18);
	Maker m2(m1);
	cout << "m1.id:" << m1.mId << " m1.age:" << m1.mAge << endl;
	cout << "m2.id:" << m1.mId << " m2.age:" << m2.mAge << endl;
    //m2.mId=m1.mId;
	//m2.mAge=m1.mAge;
}

void test02()
{
	Student s1("露琪亚", 18);
	Student s2(s1);

	cout << "s1.Name=" << s1.pName << " s1.age=" << s1.age << endl;
	cout << "s2.Name=" << s2.pName << " s2.age=" << s2.age << endl;
}

int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

上面这段代码中test02()是错误的,原因在于:同一块空间会被释放两次
c++学习——构造函数和析构函数_第8张图片
因此引入深拷贝,用深拷贝来解决浅拷贝
c++学习——构造函数和析构函数_第9张图片

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Maker
{
public:
	Maker(int id, int age)
	{
		mId = id;
		mAge = age;
	}
public:
	int mId;
	int mAge;
};

class Student
{
public:
	Student(const char *name, int Age)
	{
		pName = (char*)malloc(strlen(name));
		strcpy(pName, name);
		age = Age;
	}
	//深拷贝
	Student(const Student &stu)
	{
		cout << "自动写的拷贝构造函数" << endl;
		//1、申请空间
		pName = (char*)malloc(strlen(stu.pName) + 1);
		//2、拷贝数据
		strcpy(pName, stu.pName);
		age = stu.age;
	}
	//写析构函数释放
	~Student()
	{
		cout << "析构函数" << endl;
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
public:
	char *pName;
	int age;
};

void test01()
{
	Maker m1(1, 18);
	Maker m2(m1);
	cout << "m1.id:" << m1.mId << " m1.age:" << m1.mAge << endl;
	cout << "m2.id:" << m1.mId << " m2.age:" << m2.mAge << endl;
    //m2.mId=m1.mId;
	//m2.mAge=m1.mAge;
}

void test02()
{
	Student s1("露琪亚", 18);
	Student s2(s1);

	cout << "s1.Name=" << s1.pName << " s1.age=" << s1.age << endl;
	cout << "s2.Name=" << s2.pName << " s2.age=" << s2.age << endl;
}

int main()
{
	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

c++学习——构造函数和析构函数_第10张图片

补充:初始化列表

#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;

class Person
{
public:
	//传统初始化操作
	//Person(int a, int b, int c)
	//{
	//	m_A = a;
	//	m_B = b;
	//	m_C = c;
	//}

	//利用初始化列表来初始化属性

	Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
	{

	}

	int m_A;
	int m_B;
	int m_C;
};

void test01()
{
	//Person p(10, 20, 30);
	Person p(30,20,10);
	cout << "m_A= " << p.m_A << endl;
	cout << "m_B= " << p.m_B << endl;
	cout << "m_C= " << p.m_C << endl;
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

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