对象的初始化与清理部分_2

news/2024/11/19 9:31:45/

五、深拷贝与浅拷贝

浅拷贝:简单的拷贝赋值操作

深拷贝:在堆区重新开辟空间,进行拷贝操作

下面举例解释:

创建person类与测试函数

class person
{
public:person(){cout << "person默认构造函数调用" << endl;}person(int age, int height){m_age = age;m_height = new int(height);cout << "person有参构造函数调用" << endl;}~person(){cout << "person析构函数调用" << endl;}int m_age;int* m_height;
};void test01()
{person p1(22,179);cout << "年龄为" << p1.m_age << "身高为" << *p1.m_height << endl;person p2(p1);cout << "年龄为" << p2.m_age << "身高为" << *p2.m_height << endl;
}

此时p1/p2的各个属性都是相同

而此时,由于属性中m_height是我们new出的堆区的数据,需要我们手动释放,因此我们在析构函数中写出释放的部分

	~person(){if (m_height != NULL){delete m_height;m_height = NULL;}cout << "person析构函数调用" << endl;}

再次运行

 程序直接崩了

因为编译器自己的拷贝构造函数是浅拷贝操作

 浅拷贝带来的问题就是堆区内存重复释放

因此,使用深拷贝解决,我们自己创建一块堆区保存数据,即自己实现拷贝构造函数

person(const person& p){m_age = p.m_age;//m_height = p.m_height; //编译器默认实现,即浅拷贝m_height = new int(*p.m_height);cout << "person拷贝构造函数调用" << endl;}

 成功实现

 总结:如果属性有在堆区开辟的,自己要提供拷贝构造函数,防止浅拷贝带来问题

六、初始化列表

作用:使用初始化列表语法来初始化属性

语法:

构造函数() : 属性1(值1),属性2(值2),属性3(值3)...
{;
}

例:

一般情况下,我们初始化是创建对象同时赋值

class person
{
public: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);cout << p.m_a << endl;cout << p.m_b << endl;cout << p.m_c << endl;
}

接下来使用初始化列表的方式初始化值

class person
{
public:person() :m_a(30), m_b(20), m_c(10){;}int m_a;int m_b;int m_c;
};
void test01()
{person p;cout << p.m_a << endl;cout << p.m_b << endl;cout << p.m_c << endl;
}

这样就实现了列表初始化值,不过这样初始化的值是固定的,可以进一步优化

七、类对象作为类成员

C++中某个类的成员可以是另一个类的对象,称该成员为对象成员


创建2个类:person类与car类,在person中定义2个属性,1个是人名,1个是车名,而车名来自于car类

class car // 车类
{
public:car(string car){c_car = car;cout << "car的执行" << endl;}string c_car;
};
class person // 人类
{
public:person(string name, string c_car) :m_name(name), m_car(c_car){cout << "person的执行" << endl;}string m_name;car m_car;
};
void test01()
{person p("Joyce", "BMW");cout << p.m_name << "开着" << p.m_car.c_car << endl;
}
int main()
{test01();return 0;
}

而两个类,哪个先执行,哪个先销毁

分别在2个类中增加一句person/car的执行,即可得知哪个先执行

分别在2个类中增加析构函数并输出内容,即可得知哪个先销毁

class car
{
public:car(string car){c_car = car;cout << "car的执行" << endl;}~car(){cout << "car析构的执行" << endl;}string c_car;
};
class person
{
public:person(string name, string c_car) :m_name(name), m_car(c_car){cout << "person的执行" << endl;}~person(){cout << "person析构的执行" << endl;}string m_name;car m_car;
};

总结:

①先调用对象成员的构造,再调用本类的构造

②析构刚好相反 

八、静态成员

含义:即在成员变量和成员函数前加上关键字static,称为静态成员

分类:

静态成员变量所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化
静态成员函数所有对象共享同一个函数
静态成员函数只能访问静态成员变量

例①:静态成员变量

class person
{
public:static int m_age;
};
void test01()
{person p;cout << p.m_age << endl;
}
int main()
{test01();return 0;
}

简单创建p,尝试运行p中的静态成员变量,会直接报错,因为编译不过去

	//	①通过对象进行访问person p;cout << p.m_age << endl;//	②通过类名进行访问cout << person::m_age << endl;

 这时需要加上类外初始化

类外随便加一句

int person::m_age = 52;

同时,静态成员变量有2种访问方式

①通过对象进行访问

②通过类名进行访问

	//	①通过对象进行访问person p;cout << p.m_age << endl;//	②通过类名进行访问cout << person::m_age << endl;

而对象访问这里我们再创建一个变量,即可验证静态成员变量共享同一块数据

void test02()
{//	①通过对象进行访问person p;cout << p.m_age << endl;person p2;p2.m_age = 66;cout << p.m_age << endl;
}

2次都输出p.m_age


同时,静态成员变量也有访问权限

class person
{
private:int m_a;
};
int person::m_a = 22;

尝试cout输出

 例②:静态成员函数

整体与静态成员变量规则相同,只不过在函数前加上static

class person
{
public:static	void func(){m_a = 55;cout << "func的调用" << endl;}static int m_a;
};
int person::m_a = 50;
void test01()
{// 通过对象访问person p;p.func();// 通过类名访问person::func();
}
int main()
{test01();return 0;
}


不过,首先静态成员函数只能访问静态成员变量

class person
{
public:static	void func() // 静态成员函数{m_a = 55;m_b = 10;cout << "func的调用" << endl;}static int m_a; // 静态成员变量int m_b;	// 普通成员变量
};

 直接报错


同时,静态成员函数也有访问权限

class person
{
private: // 私有权限static	void func2() // 静态成员函数{cout << "func2的调用" << endl;}
};

不可访问 


http://www.ppmy.cn/news/39832.html

相关文章

node安装

一、下载nodejs的安装包&#xff1a; 下载地址&#xff1a;https://nodejs.org/zh-cn/download 根据自己电脑系统及位数选择&#xff0c;一般都选择windows64位.msi格式安装包 二、改变nodejs的下载依赖包路径 安装完nodejs后&#xff0c;也同时安装了npm&#xff0c; npm是…

酒店拥有VR全景是一种什么样的体验?

每一家酒店都希望自己门庭若市&#xff0c;有更多的人来&#xff0c;随着信息化和互联网的发展时代的到来&#xff0c;酒店营销也逐渐加入了更多的现代元素&#xff0c;那么&#xff0c;酒店怎么样更好地利用互联网来做宣传、来获得更多的客户呢&#xff1f;VR全景作为新兴的富…

C++ Primer第五版练习题冲冲冲

第一章 1.1节练习 1.1运行结果 1.2 让程序返回-1时运行结果 1.3 标准输出打印 hello&#xff0c;world 这些题太无聊了。。选择性的写吧。。 1.6 如果合法&#xff0c;将会输出The sum of x1 and x2 is x3 如果不合法&#xff0c;则可以把语句的前两个;去除&#xff0c;代码…

2023年 合肥市瑶海区信息学竞赛区赛 小学组

2023年 合肥市瑶海区信息学竞赛区赛 小学组T1.计算面积 题目描述 小开是瑶海某小学的学生。在数学课上,小开的数学老师孟老师教会了大家梯形面积的计算公式:梯形面积=(上底+下底)*高/2。孟老师布置了多个关于梯形面积的计算题,作为当天的家庭作业。小开在完成了题目以后,…

要不你给我说说什么是长轮询吧?

Apollo: 配置修改后能够实时推送到应用端&#xff0c;并且具备规范的权限、流程治理等特性&#xff0c;适用于微服务配置管理场景。 支持(HTTP长轮询1s内), 用户在Apollo修改完配置并发布后&#xff0c;客户端能实时&#xff08;1秒&#xff09;接收到最新的配置&#xff0c;并…

Ubuntu配置Opencv

1、Cmake 的编译及安装 OPENCV的编译依赖Cmake&#xff0c;所以首先需要安装Cmake 通过命令行的方式安装&#xff08;前提是需要Ubuntu联网&#xff09; mlml-virtual-machine:~$ sudo apt-get install cmake 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成…

【计算机网络-网络层】路由选择协议

文章目录1 路由器与路由选择1.1 路由器1.2 路由表&#xff08;RIB 表&#xff09;1.2.1 路由表项1.2.2 动态路由1.2.3 静态路由1.2.4 直连路由1.3 转发表&#xff08;FIB 表&#xff09;1.4 自治系统 AS2 内部网关协议 IGP——路由信息协议 RIP2.1 RIP 规定2.2 RIP 的工作原理2…

归并排序及常见面试题

⭐️前言⭐️ 本篇文章主要介绍归并排序&#xff0c;以及与之相关的改写问题&#xff0c;将该类问题总结归纳&#xff0c;便于后续遇见类似题目时候的解答。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持…