20240416,对象初始化和清理,对象模型和THIS指针

 哈哈哈乌龟越狱了

目录

2.5 深拷贝&浅拷贝

2.6 初始化列表

2.7 类对象作为类成员

2.8 静态成员

2.9 成员变量和成员函数分开存储

2.10 THIS指针的用途

2.11 空指针访问成员函数

2.12 COSNT修饰成员函数

2.5 深拷贝&浅拷贝

浅拷贝:简单的赋值拷贝炒作
深拷贝:在堆区重新申请空间进行拷贝操作

浅拷贝带来的问题就是堆区的内存重复释放;深拷贝是?拷贝的时候重新申请一块内存,记录的数据是一样的,指向的内存是不一样的?

20240411,内存分区模型,new-delete语句-CSDN博客(一些根本不复习学了就忘还找不到笔记人士,乐,还好学的不多?/不是)

如果属性在堆区开辟的,一定要自己构造深拷贝函数避免出现问题

#include<iostream>
using namespace std;
class Person
{
public:
	int m_age;
	int* m_height;//指针接收
	Person()
	{
		cout << "Persong 默认构造 函数的调用" << endl;
	}
	Person(int age,int height)
	{
		m_age = age;
		m_height=new int(height);//把身高创建在堆区,new返回的是该数据类型的指针
		cout << "Persong 有参构造 函数的调用" << endl;
	}
	//系统提供的拷贝函数是浅拷贝
	//自己写一个深拷贝构造函数,解决深拷贝带来的问题
	Person(const Person &p)
	{
		m_age = p.m_age;
		//m_height = p.m_height;编译器写的
		m_height = new int(*p.m_height);
		//在堆区申请一块区域,记录*p_height的内容,即,在堆区创建数据*p_hright
		//此时new int(height)没有释放
		cout << "Persong 拷贝构造 函数的调用" << endl;
	}
	~Person()
	{
		if (m_height != NULL)
		{
			delete m_height;//释放
			m_height = NULL;//初始化
		}
		cout << "Persong 默认析构 函数的调用" << endl;//将堆区开辟的数据做释放操作
	}
};
void test01()
{
	Person p1(28,180);//执行了一次析构函数,指针指向的内存已经被释放掉了
	cout << "p1的年龄为" << p1.m_age <<"身高为"<<*p1.m_height << endl;
	Person p2(p1);
	//拷贝了m_height记录的地址,此时m_height不为空,
	//但是地址指向的地方已经被释放了,再进行一次释放,非法操作
	cout << "p2的年龄为" << p2.m_age << "身高为" << *p2.m_height << endl;
	//函数结束一起释放
}
int main()
{
	test01();
	system("pause");
	return 0;
}
2.6 初始化列表

构造函数():属性1(值 1),属性2(值2)···{ }
构造函数(int a ,int b ,```):属性1(a),属性2(b)···{ }

#include<iostream>
using namespace std;
class Person
{
public:
	int m_a;
	int m_b;
	int m_c;
	Person () :m_a(10), m_b(20), m_c(30) {}//不能修改数值
	Person(int a, int b, int c) :m_a(a),m_b(b),m_c(c){}//可以修改
};
void test01()
{
	Person p;
	Person p1(540, 23, 45);//int a=540,m_a(a)
	cout << p.m_a << "\t" << p.m_b << "\t" << p.m_c << endl;
	cout << p1.m_a << "\t" << p1.m_b << "\t" << p1.m_c << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}
2.7 类对象作为类成员

俺的BUG:没有特意创建一个子对象,无法输出被嵌套的子对象
构造和析构的顺序相反

#include<iostream>
#include<string>
using namespace std;
class Phone
{
public:
	string m_Pname;
	Phone(string Pname)
	{
		m_Pname = Pname;
		cout << "Phone的 构造函数  调用" << endl;
	}
	~Phone()
	{
		cout << "Phone的 析构函数  调用" << endl;
	}
};
class Person
{
public:
	string m_Name;
	Phone m_Phone;
	Person(string name, string phone) :m_Name(name), m_Phone(phone) 
	{
		cout << "Person的 构造函数  调用" << endl;
	}
	~Person()
	{
		cout << "Person的 析构函数  调用" << endl;
	}//先释放PERSON的,再释放PHONE的
};
void test01()
{
	Person p("张三", "华为p60");
	cout << p.m_Name  << endl;//先构造了一个Phone类,先调用了PHONE的构造函数,再PERSON的构造函数
	//cout << p.m_Name << "拿了" << p.m_Phone << endl;//编译错误
	//说没有 操作数 能匹配<<的运算符
}
int main()
{
	test01();
	system("pause");
	return 0;
}
2.8 静态成员

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

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	//(全局?共享),编译分配,类内声明&类外初始化(否则无法访问)
	static int m_a;
	int m_c;
	static void func()
	{
		m_a = 999;
		//m_c = 888;//静态成员函数只能访问静态成员变量   因为所有对象共享,无法区分m_c属于哪一个对象?
		cout << "静态成员函数  func() 的调用" << endl;
	}
private:
	//静态成员变量,函数 也有访问权限
	static int m_b;
	static void func2()
	{
		cout << "private 静态成员函数  func() 的调用" << endl;
	}
};
//类外初始化,初始化了之后,没有修改的情况下,就是100
int Person::m_a = 100;
int Person::m_b = 300;

void test01()
{
	Person p;
	cout << p.m_a << endl;//无法解析的外部符号
	Person p2;
	cout << p2.m_a << endl;//通过对象访问
	p2.m_a = 200;
	cout << p2.m_a << endl;
	cout << p.m_a << endl;//输出200,P和P1共享这一个静态变量
}
void test02()
{
	//静态成员变量,不属于某个对象上,所有对象共享同一份数据
	//两种访问方式:通过对象,通过类名
	cout << Person::m_a << endl;
	//cout << Person::m_b << endl;//m_b是私有作用域,不能类外访问
}
void test03()
{
	//静态成员函数访问:对象,类名
	Person::func();
	Person p,p1;
	p.func();
	p1.func();
	//Person::func2();无权限
}
int main()
{
	test02();//输出100
	cout << endl;
	test01();
	cout << endl;
	test02();//输出200,
	cout << endl;
	test03();
	test02();
	system("pause");
	return 0;
}
2.9 成员变量和成员函数分开存储

只有非静态的变量才在对象上

#include<iostream>
#include<string>
using namespace std;

class Person
{

};
class Pers
{
	int m_a;
	int m_b;
	static int m_c;//不属于类的对象上
	void func(){}//也
	static void func2(){}//也
};
int Pers::m_c = 800;
void test01()
{
	Person p;
	cout << "size of Person p=" << sizeof(p) << endl;
	//空对象占用内存 1
	//C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
	//(区分不同的空对象)每个空对象也应该有一个独一无二的内存地址
}
void test02()
{
	Pers p;
	cout << "size of Pers p=\t" << sizeof(p) << endl;//内存对齐成员变量
}
int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}
2.10 THIS指针的用途

每一个非静态成员函数只会诞生一份函数实例,也就是多个同类型的对象会公用一块代码,this指针指向被调用的成员函数所属的对象
THIS指针是隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用
用途:当形参和成员变量同名时,可以用THIS指针来区分;在类的非静态成员函数中返回对象本身,可以使用 RETURN *THIS

#include<iostream>
#include<string>
using namespace std;
//解决名称冲突
class Person
{
public:
	int age;
	Person(int age)
	{
		//age = age;//编译器认为三个age是同一个,没有和成员变量区分开
		this->age = age;//this指针指向被调用的成员函数所属的对象
	}
	void Personaddage(Person& p)
	{
		this->age += p.age;//两个变量的AGE相加 || 一个变量的AGE累加
	}
	//用引用来接收
	Person& Personaddage1(Person& p)
	{
		this->age += p.age;//两个变量的AGE相加 || 一个变量的AGE累加
		return *this;//返回对象本身
	}
	Person Personaddage2(Person& p)
	{//返回值
		this->age += p.age;
		return *this;
	}
};

void test01()
{
	Person p1(18);
	cout << "p1的年龄是  " << p1.age << endl;
}
void test02()
{
	Person p(80);
	p.Personaddage(p);
	cout << "p的年龄是  " << p.age << endl;
	Person p1(2);
	p.Personaddage(p1);
	cout << "p的年龄是  " << p.age << endl;
	//p.Personaddage(p1).Personaddage(p1).Personaddage(p1).Personaddage(p1);
	//超级连加,错误,第一次函数运算完成,返回一个VOID
	p.Personaddage1(p1).Personaddage1(p1).Personaddage1(p1).Personaddage1(p1);//链式编程思想
	cout << "p的年龄是  " << p.age << endl;
	p.Personaddage2(p1).Personaddage2(p1).Personaddage2(p1).Personaddage2(p1);//链式编程思想
	//只运算了第一次,值返回就是?复制一份?和本体值相同,但是不是本体了
	cout << "p的年龄是  " << p.age << endl;
}
int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}
2.11 空指针访问成员函数

C++中空指针也是可以调用成员函数,但是也要注意有么有用到THIS指针
如果用到,需要加以判断保证代码的健壮性?

#include<iostream>
#include<string>
using namespace std;
//解决名称冲突
class Person
{
public:
	int m_age;
	void showPersonName()
	{
		cout << "this is Person Class" << endl;
	}
	void showPersonAge()
	{
		if (this == NULL)
		{
			return;//不会走到下一步
		}
		cout << "m_age=" << m_age << endl;
		//cout << "m_age=" << this->m_age << endl;但是this现在是一个空指针,
	}
};

void test01()
{
	Person* p = NULL;
	p->showPersonName();
	//p->showPersonAge();//报错
}

int main()
{
	test01();
	system("pause");
	return 0;
}
2.12 COSNT修饰成员函数

成员函数后加CONST后-》常函数;常函数不可以修改成员属性,成员属性声明时加关键字MUTABLE后,常函数中依然可修改
在成员函数后加CONST,本质上修饰的时THIS指针,让指针指向的值也不可修改
常对象:声明对象前加CONST,常对象只能调用常函数

#include<iostream>
#include<string>
using namespace std;
//解决名称冲突
class Person
{
public:
	int m_age;//不能直接设置一个初始值,反而会报错受用未初始化的内存p
	mutable int m_b;//特殊变量,常函数中也可以修改
	void showage()const//(const) Person *const this
	//在成员函数后加CONST,本质上修饰的时THIS指针,让指针指向的值也不可修改
	{
		//m_age = 100;不可修改
		//this->m_age = 100;
		//this 指针的本质,指针常量,指针的指向不可修改,Person *const this
		//this = NULL;不可修改
		cout << "m_age=" << m_age << endl;
		m_b = 232;
		cout << "m_b=" << m_b << endl;//特殊变量可以修改
	}
	void func(){}
};
void test01()
{
	Person p;
	p.showage();
}
void test02()
{
	const Person p;//常对象
	//p.m_age = 1000;//不可修改
	p.m_b = 454;//可以修改
	p.showage();//常对象只能调用常函数
	//p.func();//不可以调用普通成员函数,因为普通成员函数可以修改属性
}
int main()
{
	test01();
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/550599.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode-合并两个有序链表

目录 题目 图解 方法一 方法二 代码(解析在注释中) 方法一 ​编辑方法二 题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1…

第11章 数据仓库和数据智能知识点梳理

第11章 数据仓库和数据智能知识点梳理&#xff08;附带页码&#xff09; ◼ 数据仓库&#xff08;Data Warehouse&#xff0c;DW&#xff09;&#xff1a;始于 20 世纪 80 年代&#xff0c;发展于 20 世纪 90 年代&#xff0c;后与商务智能&#xff08;Business Inteligence,BI…

MAC上如何将某个目录制作成iso格式磁盘文件,iso文件本质是什么?以及挂载到ParallelDesktop中?(hdiutil makehybrid )

背景 ParallelsDesktop没有安装ParallelsTools的无法共享目录&#xff0c;可以通过ParallelsDesktop提供CD磁盘的方式共享进去 命令 # 准备文档 mkdir mytestdir cp xxx mytestdir# 生成iso hdiutil makehybrid -o output.iso mytestdir -iso -joliethdiutil是MAC提供的磁盘…

使用FastDDS编译IDL文件

1.安装FastDDS环境 Ubuntu22.04 1.1安装依赖的软件 sudo apt-get update //基础工具安装 sudo apt install cmake g python3-pip wget git //Asio 是一个用于网络和低级 I/O 编程的跨平台C库&#xff0c;它提供了一致的 异步模型。 TinyXML2是一个简单&#xff0c;小巧&…

DFS算法系列题 全排列II

DFS算法系列题 – 全排列II DFS精选题- > 这次我们挑战的对象是&#xff1a; 全排列II 题目链接&#xff1a;47. 全排列 II - 力扣&#xff08;LeetCode&#xff09; 这道题和我们之前做的全排列不同的点在于这道题的题目包含了重复的数字&#xff0c;要求我们返回不重复…

Transformer的Decoder的输入输出都是什么

目录 1 疑问&#xff1a;Transformer的Decoder的输入输出都是什么 2 推理时Transformer的Decoder的输入输出 2.1 推理过程中的Decoder输入输出 2.2 整体右移一位 3 训练时Decoder的输入 参考文献&#xff1a; 1 疑问&#xff1a;Transformer的Decoder的输入输出都是什么 …

SQLite数据库中JSON 函数和运算符

返回&#xff1a;SQLite—系列文章目录 上一篇:维护SQLite的私有分支&#xff08;二十六&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 ​ 1. 概述 默认情况下&#xff0c;SQLite 支持 29 个函数和 2 个运算符 处理 JSON 值。还有两个表值函数可用于分解 JSON…

最优算法100例之52-合并两个单调递增的单链表

专栏主页&#xff1a;计算机专业基础知识总结&#xff08;适用于期末复习考研刷题求职面试&#xff09;系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 合并两个单调递增的单链表 题解报告 解法1&#xff1a;采用尾插法首先确定一个头结点出来&a…

【Java EE】关于Spring MVC 响应

文章目录 &#x1f38d;返回静态页面&#x1f332;RestController 与 Controller 的关联和区别&#x1f334;返回数据 ResponseBody&#x1f38b;返回HTML代码片段&#x1f343;返回JSON&#x1f340;设置状态码&#x1f384;设置Header&#x1f338;设置Content-Type&#x1f…

【halcon】C# halcon 内存暴增 续,找到一个解决方案

这里写自定义目录标题 背景释放临时缓存具体的使用感受背景 在之前的文章《【halcon】C# halcon 内存暴增 》中我们提到了一些会导致内存暴增的原因。 其中一个就是使用了计算复杂的算子,且图片很大时,此时内存就会暴增,而且内存无法被释放。 这次,我在做一个项目时,用到…

一个开源的全自动视频生成软件MoneyPrinterTurbo

只需提供一个视频 主题 或 关键词 &#xff0c;就可以全自动生成视频文案、视频素材、视频字幕、视频背景音乐&#xff0c;然后合成一个高清的短视频。 一&#xff1a;功能特性 完整的 MVC架构&#xff0c;代码 结构清晰&#xff0c;易于维护&#xff0c;支持 API 和 Web界面…

软件杯 深度学习图像修复算法 - opencv python 机器视觉

文章目录 0 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs最后 0 前言 &#…

复习回顾ES6基础篇(一小时学会es6)

基本语法 多行注释 /* 这里的所有内容 都是注释。 */单行注释 // 这是一条注释。变量定义 var x "" //定义范围变量 let y "" //定义局部变量 const z "" //定义常量运算符 变量类型 流程语句 if (condition) {/* 条件为真时运行的代…

LVM与磁盘配额

目录 一.LVM概述 1.LVM &#xff08;Logical Vokume Manager &#xff09;逻辑卷管理 2.LVM的管理命令 3.创建并使用LVM操作步骤 二.磁盘配额概述 1.实现磁盘限额的条件 2.Linux磁盘限额的特点 3.实现磁盘配额的步骤 三.总结&#xff1a; 一.LVM概述 1.LVM &#xff…

【静态分析】软件分析课程实验-前置准备

课程&#xff1a;南京大学的《软件分析》课程 平台&#xff1a;Tai-e&#xff08;太阿&#xff09;实验作业平台 1. 实验概述 Tai-e 是一个分析 Java 程序的静态程序分析框架&#xff0c;相比于已有的知名静态程序分析框架&#xff08;如 Soot、Wala 等&#xff09;&#xf…

《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)

1.简介 页面对象模型&#xff08;Page Object Model&#xff09;在Selenium Webdriver自动化测试中使用非常流行和受欢迎&#xff0c;作为自动化测试工程师应该至少听说过POM这个概念。本篇介绍POM的简介&#xff0c;接下来宏哥一步一步告诉你如何在你JavaSelenium3自动化测试…

算法打卡day36

今日任务&#xff1a; 1&#xff09;01背包问题理论基础(卡码网&#xff1a;46. 携带研究材料) 2&#xff09;01背包问题滚动数组(卡码网&#xff1a;46. 携带研究材料) 3&#xff09;416. 分割等和子集 4&#xff09;复习day11 卡码网&#xff1a;46. 携带研究材料 题目链接&…

35、链表-LRU缓存

思路&#xff1a; 首先要了解LRU缓存的原理&#xff0c;首先定下容量&#xff0c;每次get请求和put请求都会把当前元素放最前/后面&#xff0c;如果超过容量那么头部/尾部元素就被移除&#xff0c;所以最近最少使用的元素会被优先移除&#xff0c;保证热点数据持续存在。 不管放…

排序(三)——快速排序(递归以及栈和队列实现非递归)超详细

目录 1.hoare法 2.挖坑法 3.前后指针法 4.快排的非递归 4.1 栈实现快排非递归 4.2 队列实现快排非递归 快排我们之前在学习通讯录的时候就用了&#xff0c;那时候我们知道快排是一个很牛逼的排序算法&#xff0c;那他到底是怎么实现的呢&#xff1f; 1.hoare法 快速排序…

【Redis 神秘大陆】003 数据类型使用场景

三、Redis 数据类型和使用场景 Hash&#xff1a;对象类型的数据&#xff0c;购物车List&#xff1a;队列/栈Set&#xff1a;String类型的无序集合&#xff0c;intset&#xff0c;抽奖、签到、打卡&#xff0c;商品评价标签Sorted Set&#xff1a;存储有序的元素&#xff0c;zip…