构造函数和析构函数

C++构造和析构



提示:以下是本篇文章正文内容,下面案例可供参考

一、构造函数

什么是构造函数

  • 函数名和类名相同
    没有返回值
    print()

  • 如果不写构造函数,任何类中都存在一个默认的构造函数
    默认的构造函数是无参的

在这里插入代#include <iostream>
#include <string>
using namespace std;
class student
{
public:
	void print()
	{
		cout << name << " " << age << endl;
	}
protected:
	string name = "lisa";
	int age = 18;
};

int main()
{
	student stu;
	stu.print();
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • 当我们自己写了构造函数,默认的构造函数就不存在
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
	student(string sName, int sAge)
	{
		name = sName;
		age = sAge;
	}
	void print()
	{
		cout << name << " " << age << endl;
	}
protected:
	string name = "lisa";
	int age = 18;
};

int main()
{
	//student stu;构造无参的对象,需要无参构造函数
	//stu.print();
	student stu("lisi", 18);
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

构造函数在构造对象的时候调用
在这里插入代码片
  • delete可以用来删掉默认的函数 删掉默认的构造函数意味着不能构造对象
    student() = delete;

  • 指定使用默认的无参构造函数,用default说明

  • 允许构造函数调用另一个构造函数,只是要用初始参数列表的写法
    避免形参名和数据成员名字相同的导致问题

#include <iostream>
#include <string>
using namespace std;
class call
{
public:
	call(string name, int age) :name(name), age(age){}
	//委托构造:允许构造函数调用另一个构造函数
	call() :call{ "默认", 18 }{}	//没有给数据初始化
	void print()
	{
		cout << name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};
int main()
{

	call test;
	test.print();
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • 初始化参数列表:只有构造函数有
    构造函数名(参数1,参数2…):成员1(参数1),成员2(参数2)…
//初始化参数列表的写法
string name = "lisi";
class list
{
public:
	list(string sname=" ", int sage=18) :name(sname), age(sage)
	{
		cout << "初始化参数列表" << endl;
		//继承和类的组合必须采用初始化参数列表写法
	}
	list(int age) :name(name), age(age){}	//通过全局变量初始化参数列表
protected:
	string name;
	int age;
};

构造函数用来做什么

  • 构造函数用来构造对象
    构造函数更多是用来初始化数据成员

思考题

为什么不写构造函数可以构造对象?
是因为存在一个默认的无参构造函数,所以可以构造无参对象
构造函数重载是为了什么?
为了构造不同长相的对象
#include <iostream>
#include <string>
using namespace std;
//为了能够构造不同长相的对象,我们会给构造函数缺省处理
class Teach
{
public :
	Teach(string tname=" ", int tage=19)
	{
		name = tname;
		age = tage; 
	}
	//上面函数等效可以实现下面三个函数的功能
	//Teach(){}
	//Teach(string sName){ name = sName; }
	//Teach(string sName, int sAge){ name = sName, age = sAge; }
protected:
	string name;
	int age;
};
int main()
{

	Teach teach1;
	Teach teach2("张三");
	Teach teach3("李四",18);
	while (1);
	return 0;
}

二、析构函数

1.析构函数是什么样的

  • 无返回值
  • 无参数
  • 函数名:-类名
  • 不写的话会存在默认的析构函数,析构函数不能重载
  • 析构函数不需要自己调用,对象消失之前会调用析构函数
#include <iostream>
using namespace std;
class Student
{
public:
	Student(const char* pstr, int age) :age(age)
	{
		str = new char[strlen(pstr) + 1];
		strcpy_s(str,strlen(pstr)+1, pstr);
	}
	void print()
	{
		cout << str << "\t" << age << endl;
	}
	~Student();
protected:
	char *str;
	int age;
};
Student::~Student()
{
	cout << "我叫做析构函数" << endl;	//释放内存放在析构函数内完成
	delete[]str;
}
int main()
{
	{
		Student student("张三", 18); 
		student.print();
	}
	cout << "主函数" << endl;
	//new一个对象的时候,只有delete才会调用析构函数
	{
		Student*pObject = new Student("zhangsan", 12);
		delete pObject;
		pObject = nullptr;
	}
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

2.析构函数用来做什么?(什么时候需要自己手动写析构函数)

  • 当类中的数据成员是指针的时候,并且动态申请内存就需要手写析构
  • 析构函数用来释放数据成员申请动态内存

三、拷贝构造函数

1.拷贝构造函数也是构造函数

  • 拷贝构造函数长相和构造函数一样的,只是参数是固定
    拷贝构造函数唯一的参数是对对象引用
  • 不写拷贝构造函数,也存在一个默认的拷贝构造函数
  • 拷贝构造函数作用: 通过一个对象去初始化另一个对象

2. 问题?

 什么时候调用拷贝构造?
	 当通过一个对象去创建出来另一个新的对象时候需要调用拷贝
  • 拷贝构造什么时候需要加const修饰参数?
    当存在匿名对象赋值操作的时候,必须要const修饰
#include <iostream>
#include <string>
using namespace std;

class Student{
public:
	Student() = default;
	Student(const char* name, int age) :name(name), age(age){}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	//拷贝构造
	Student(const Student& lisi)
	{
		name = lisi.name;	//zhangsan.name=lisi.name
		age = lisi.age;		//zhangsan.name=zhangsan.name
		cout << "拷贝构造" << endl;
	}

protected:
	string name;
	int age;
};
void printData(Student lisi)	//student lisi=实参
{
	cout << "拷贝构造" << endl;
	lisi.print();
}
void printData2(Student &lisi)	//不存在拷贝构造,实参就是形参 形参就是实参
{
	lisi.print();
}
int main()
{
	Student lisi("lisi", 18);
	lisi.print();
	//显式调用
	cout << "显式调用" << endl;
	Student zhangsan(lisi);	//通过一个对象创建另一个对象
	zhangsan.print();
	//隐式调用
	cout << "隐式调用" << endl;
	Student wangwu = lisi;	//拷贝构造
	Student xiaoming;
	xiaoming = lisi;		//运算符重载
	xiaoming.print();
	//函数传参
	cout << "第一种调用形态" << endl;
	printData(lisi);
	cout << "第二种调用形态" << endl;
	printData2(lisi);

	//无名对象 匿名对象临时对象是一个常属性的
	Student temp;
	temp = Student("匿名", 18);
	temp.print();

	//匿名对象创建对象的时候,拷贝构造一定要用const修饰 匿名对象是一个右值
	Student temp2 = Student("匿名", 19);
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

深浅拷贝

  • 浅拷贝: 默认的拷贝构造叫做浅拷贝
  • 深拷贝:拷贝构造函数中做了new内存才做,并且拷贝赋值的操作
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;

class Student
{
public:
	Student(const char* mname, int age) :age(age)
	{
		name = new char[strlen(mname) + 1];
		strcpy_s(name, strlen(mname) + 1, mname);
	}
	void print()
	{
		cout << name << "\t" << age <<endl;
	}
	Student(const Student& object) //深拷贝
	{
		//name=object.name;
		name = new char[strlen(object.name) + 1];
		strcpy_s(name,strlen(object.name)+1, object.name);
		age = object.age;
	}
	~Student()
	{
		delete[] name;
	}
protected:
	char* name;
	int age;

};

int main()
{
	{
		//浅拷贝	运行时会重复释放
		Student lisi("lisi", 20);
		Student zhangsan(lisi);
		Student wangwu = lisi;
		lisi.print();
		zhangsan.print();
		wangwu.print();
	}
	while (1);
	return 0;
}

在这里插入图片描述

4、构造和析构顺序问题

  • 普通对象,构造顺序和析构顺序是相反的
  • new出来的对象,delete会直接调用析构函数
  • static对象,当程序释放的时候,生命周期才结束,所以是最后释放
#include <iostream>
#include <string>
using namespace std;
class Student 
{
public:
	Student(string name = "x") :name(name) {
		cout << name;
	}
	~Student(){
		cout << name;
	}
protected:
	string name;
};
int main() 
{
	{
		Student stu1("A");			//A
		static Student stu2("B");		//B   程序关闭时候才死亡,最后析构
		Student* stu3 = new Student("C");	//C
		Student stu4[4];				//xxxx
		delete stu3;				//C  delete 直接调用析构
		stu3 = nullptr;
								//xxxxAB
	}
	while (1);
	return 0;
}

运行结果:

ABCxxxxCxxxxAB

C++结构体

#include <iostream>
#include <string>
using namespace std;
struct Student
{
	//默认为公有属性
	//类中默认属性是私有属性
//protected:
	string name;
	int age;
public:
	Student(string name) :name(name) 
	{
		cout << "构造函数" << endl;
	}
	Student(const Student& object) 
	{
		name = object.name;
		age = object.age;	
		cout << "拷贝构造" << endl;
	}
	~Student() 
	{

	}
};
int main() 
{
	//采用创建时候赋值的方式,也是调用构造函数
	//MM object = { "lisa",19 };  错误,因为没有两个参数的构造函数
	Student object = { "lisa" };
	cout << object.name << "\t" << object.age << endl;
	//C++结构体一旦写了构造函数,就必须按照C++类的方式的去用
	Student mm(object);
	cout << mm.name << "\t" << mm.age << endl;
	return 0;
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值