C++[类和对象+构造函数和析构函数]

2023-3-7首次编辑

Unit 4:类和对象

一.概念

类:

  • 自定义数据类型(C语言的结构体进化而成)

对象:

  • 类实例化出来的,用自定义数据类型定义的一个变量
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

//1.类
class Maker
{
public:
	int a; //成员变量(成员属性)
	void func() //成员函数(成员方法)
	{
		cout << "func" << endl;
	}
};

int main()
{
	Maker m; //2.对象
	system("pause");
	return 0;
}

二.类的封装

封装:

  • 变量(属性)函数(方法) 封装到类内
  • 然后给这些数据赋予权限

目的:

  • 防止乱调用函数和变量,出现错误
  • 维护代码更方便
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
#include "string"
using namespace std;

class Maker
{
public: //公有权限
	void set(string Name, int Id)
	{
		id = Id;
		name = Name;
	}
	void printMaker()
	{
		cout << "id=" << id << endl << "name=" << name << endl;
	}

private: //私有权限
	int id;
	string name;

protected: //保护权限
	int a;
};

void test()
{
	Maker m;
	m.set("小花", 1);
	m.printMaker();
}

int main()
{
	test();
	system("pause");
	return 0;
}

权限:

  • 类外可以访问 公有权限 的成员
  • 类外不能访问 私有/保护权限 的成员
  • 类内没有权限之分

尽量把 变量(属性) 设置为 私有权限 :

  • 可以控制 变量(属性) 的读写权限
  • 可赋予客户端访问数据的一致性
  • 可以保护 变量(属性) 的合法性

三.类和结构体的区别

  • 结构体的默认权限 : 公有的
  • 类的默认权限 : 私有的

四.初始化和清理的概念

  • 当对象产生时,必须初始化成员变量
  • 当对象销毁前,必须清理对象

  • 初始化用构造函数
  • 清理用析构函数
  • 这两个函数时编译器调用

Unit 5:构造函数和析构函数

一.概念

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

//编译器默认提供默认的构造函数和析构函数
class Maker
{
public:
	Maker()//默认的构造函数,函数体是空的
	{

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

	}
};

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

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

//B.析构函数的作用
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 << endl;
		cout << "age:" << mAge << endl;
	}

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

void test2()
{
	Maker2 m2("翠花", 18);
	m2.printMaker2();
}

int main()
{
	test1();
	test2();
	system("pause");
	return 0;
}

注意:

  1. 构造函数和析构函数的权限必须是公有的
  2. 构造函数可以重载
  3. 构造函数没有返回值,不能用void,可以有参数
  4. 析构函数没有返回值,不能用void,没有参数
  • 先构造的函数,后析构

  • 有对象产生必然会调用构造函数
  • 有对象销毁必然会调用析构函数

  • 有多少个对象产生就会调用多少次构造函数
  • 有多少个对象销毁就会调用多少次析构函数

二.拷贝构造函数

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

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

	//拷贝构造函数
	Maker1(const Maker1 &m)//形参要用引用
	{
		cout << "拷贝构造函数" << endl;
		a = m.a;
	}

	void printMaker1()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};

void test1()
{
	Maker1 m1;
	m1.printMaker1();

	//用一个已有的对象去初始化另一个对象
	Maker1 m2(m1);//调用拷贝构造函数

	//如果拷贝构造函数中的形参不是引用
	/*
	Maker1(const Maker1 m) →const Maker1 m = m1;→const Maker1 m(m1);
	{
	   cout << "拷贝构造函数" << endl;
	}

	1.Maker1 m2(m1);
	2.const Maker1 m = m1;
	3.const Maker1 m(m1);
	4.const Maker1 m = m1;
	5.进入死循环
	*/
	m2.printMaker1();
}

//编译器提供了默认的拷贝构造函数
//默认拷贝构造函数进行了成员变量的简单拷贝
class Maker2
{
public:
	Maker2()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	void printMaker2()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};

void test2()
{
	Maker2 m1;
	m1.printMaker2;
	Maker2 m2(m1);
	m2.printMaker2;
}

int main()
{
	test1();
	test2();
	system("pause");
	return 0;
}

三.拷贝构造函数调用的时机

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
	}
	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
	}
	~Maker()
	{
		cout << "析构函数" << endl;
	}
};

//1.对象以值得方式给函数参数
void func1(Maker m) //Maker m = m1; 存在一个匿名对象
{

}

void test1()
{
	Maker m1;
	func1(m1);
}

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

//3.函数的局部对象以值的方式从函数返回
//vs Debug(调试)模式下,会调用拷贝构造
//vs Release(发行)模式下不会调永拷贝构造
//Qt也不调用拷贝构造
Maker func2()
{
	Maker m; //局部对象
	cout << "局部对象的地址:" << &m << endl;
	return m;
}

void test3()
{
	Maker m1 = func2();
	cout << "m1对象的地址:" << &m1 << endl;
}

int main()
{
	test1();
	test2();
	test3();
	system("pause");
	return 0;
}

四.匿名对象

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
	}
	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
	}
	~Maker()
	{
		cout << "析构函数" << endl;
	}
};

void test()
{
	//匿名对象的声明周期在当前行
	Maker();
	Maker(10);

	//注意:如果匿名对象有名字阶,那么久不是匿名对象
	Maker m1 = Maker();
	cout << "test()函数结束" << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}

五.构造函数的分类及调用

构造函数的分类:

  1. 无参构造函数
  2. 有参构造函数
  3. 拷贝构造函数
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

class Maker1
{
public:
	Maker1()
	{
		cout << "无参构造函数" << endl;
	}
	Maker1(int a)
	{
		cout << "有参构造函数" << endl;
	}
	Maker1(const Maker1 &m)
	{
		cout << "拷贝构造函数" << endl;
	}
};

//构造函数的调用
void test1()
{
	//常用:
	Maker1 m1; //调用无参构造函数
	Maker1 m2(10); //调用有参构造函数
	Maker1 m3(m2); //调用拷贝构造函数

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

	Maker1 m7;
	m7 = m6;//赋值操作
	cout << "--------" << endl;
}

//1.如果程序员提供了有参构造
//  那么编译器不会提供默认构造函数
//  但是会提供默认的拷贝构造函数
class Maker2
{
public:
	Maker2(int a)
	{
		cout << "有参构造函数" << endl;
	}
};

void test2()
{
	//Maker2 m; //err

	Maker2 m(10); //调用有参构造函数
	Maker2 m2(m); //调用拷贝构造函数
}

//2.如果程序员提供了拷贝构造函数
//  那么编译器不会提供默认的构造函数和默认的有参构造函数
class Maker3
{
	Maker3(const Maker3 &m)
	{
		cout << "拷贝构造函数" << endl;
	}
};

void test3()
{
	//Maker3 m; //err
}

int main()
{
	test1();
	test2();
	test3();
	system("pause");
	return 0;
}

[扩展] 类默认提供的函数:

  1. 默认的构造函数
  2. 默认的析构函数
  3. 默认的拷贝构造函数
  4. 默认的赋值函数

六.多个对象的构造和析构

  • 如果类有成员对象
  • 那么先调用成员对象的构造函数
  • 再调用本身的构造函数
  • 成员对象的构造函数调用和定义顺序一样
  • 析构函数的调用顺序反之

注意:

  • 如果有成员对象
  • 那么实例化对象时
  • 必须保证成员对象的构造和析构能被调用
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
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:
	Buick buick; //成员对象
	BMW bmw; //成员对象
};

void test()
{
	Maker m;
}

int main()
{
	test();
	system("pause");
	return 0;
}

七.初始化列表

指定调用成员对象的某个构造函数

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

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

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

	Buick(int b, int c)
	{
		cout << "Buick有参构造" << endl;
	}
	~Buick()
	{
	
	}
};

class Maker
{
public:
	//初始化列表

	//注意1:初始化列表只能写在构造函数
	Maker() :bmw(10)
	{
		cout << "Maker构造" << endl;
	}

	//注意2:如果有多个对象需要指定调用某个构造函数,用逗号隔开
	Maker(int a, int b, int c) :bmw(a), buick(b, c)
	{
		cout << "Maker构造" << endl;
	}

	//注意3:如果使用了初始化列表,那么所有的构造函数都要写初始化列表
	Maker(const Maker &m) :bmw(40), buick(10, 20)
	{
		cout << "Maker拷贝构造" << endl;
	}
	~Maker()
	{

	}
private:
	//如果成员对象中给了有参构造函数
	//编译器此时不会提供默认构造函数
	//就会报错
	//所以必须得提供无参构造函数

	Buick buick; //成员对象
	BMW bmw; //成员对象
};

void test()
{
	Maker m1;
	cout << "--------" << endl;
	Maker m2(30, 10, 20);
	cout << "--------" << endl;
	Maker m3(m2);
}

int main()
{
	test();
	system("pause");
	return 0;
}

八.对象的深浅拷贝

浅拷贝:

  • 默认的拷贝构造函数进行的简单的赋值操作
  • 会出现同一块空间被释放两次的问题

深拷贝:

  • 自定义拷贝构造函数
  • 可以解决浅拷贝带来的问题
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

class Student
{
public:
	Student(const char* name, int Age)
	{
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName, name);
		age = Age;
	}

	//自定义拷贝构造函数(进行深拷贝)
	//解决浅拷贝问题
	Student(const Student &s)
	{
		cout << "自定义拷贝构造函数" << endl;

		//1.申请空间
		pName = (char*)malloc(strlen(s.pName) + 1);
		//2.拷贝数据
		strcpy(pName, s.pName);

		age = s.age;
	}

	~Student()
	{
		cout << "析构函数" << endl;
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
public:
	char *pName;
	int age;
};

void test()
{
	Student s1("小花", 18);
	Student s2(s1);
	cout << "s1 Name=" << s1.pName << endl;
	cout << "s1 age=" << s1.age << endl;
	cout << "s2 Name=" << s2.pName << endl;
	cout << "s2 age=" << s2.age << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cforikl_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值