【类与对象】封装对象的初始化及清理
C++面向对象的三大特性:封装、继承、多态。具有相同性质的对象,抽象为类。
文章目录
- 1 封装
- 1.1 封装的意义(一)
- 1.2 封装的意义(二)
- 1.3 struct 和 class区别
- 1.4 成员属性设置为私有
- 练习案例:
- 1 设计立方体类
- 2 对象的初始化和清理
- 2.1 构造函数和析构函数
- 2.2 构造函数的分类及调用
- 2.3 拷贝构造函数调用时机
- 2.4 构造函数调用规则
- 2.5 深拷贝与浅拷贝(面试提及)
- 2.6 初始化列表
- 2.7 类对象作为类成员
- 2.8 静态成员
1 封装
1.1 封装的意义(一)
- 将属性和行为作为一个整体,表现为生活的事物
- 将属性和行为加以权限控制
语法:class 类名 { 访问权限 : 属性/行为}
示例:设计一个圆类,求圆的周长
/*设计一个圆类,求圆的周长圆的周长公式: 2 * PI * 半径
*/
const double PI = 3.14;class Circle
{//访问权限
public://1、属性//半径int m_r;//2、行为//获取圆的周长double calculateZC(){return 2 * PI * m_r;}};
int main()
{system("color 1E");//通过圆类,创建具体的圆c ==>>实例化(通过一个类实例化一个具体的对象)Circle c1;//给圆对象的属性赋值c1.m_r = 10;cout << "圆的周长:" << c1.calculateZC() << endl;system("pause"); return 0;
}
示例2:设计一个学生类,属性:姓名、学号。给学生姓名和学号赋值,然后显示出姓名和学号
class Student
{
public: // 访问权限 ->公共权限//1、属性 :成员属性,成员变量string s_name;int stuId;//2、行为 :成员函数 成员方法void showStudent(){cout << "学生的姓名:" << s_name << " 学号是:" << stuId << endl;}//给姓名赋值void setName(string name){s_name = name;}//给学号赋值void setId(int id){stuId = id;}
};
int main()
{system("color 1E");//通过学生类,创建具体那个学生 ==>>实例化(通过一个类实例化一个具体的对象)Student stu1;Student stu2;//给学生对象的属性赋值stu1.setName ("张三");stu1.setId( 21202201);stu1.showStudent();stu1.s_name = "李四";stu1.stuId = 21202202;stu1.showStudent();system("pause"); return 0;
}
1.2 封装的意义(二)
说明:类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限三种:
- public:公共权限
- 成员 :类内可以访问,类外也可以访问
- protected:保护权限
- 成员: 类内可以访问,类外不可以访问
- 儿子可以访问父亲的保护内容
- private:私有权限
- 成员:类内可以访问,类外不可以访问
- 儿子不可以访问父亲的私有内容
class Person
{public:string m_name;protected:string m_Car;private: int m_Password;public:void func(){m_name = "张三";m_Car = "保时捷";m_Password = 12345;}
};
1.3 struct 和 class区别
说明:在C++中struct 和class唯一的区别在于默认的访问权限不同
区别:
- struct:默认权限为公共
- class:默认权限为私有
class C1
{int m_a; //默认权限 私有
};struct C2
{int m_a; //默认权限 公共
};
C1 c1;
//c1.m_a = 100; //报错
C2 c2;
c2.m_a = 100; //公共权限,类内类外都可以访问
1.4 成员属性设置为私有
优点:
- 将所有成员属性设置为私有之后,自己可以控制读写权限
- 对于写权限,检测数据的有效性
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;/*成员属性设置为私有1、可以自己控制读写权限 --某些属性的读写2、对于以检测数据的有效性 --对于年龄的特殊设置*/
//设计人类
class Person
{
public://设置姓名void setName(string name){m_Name = name;}//获取姓名string getName(){return m_Name;}int setAge(int age){m_Age = 0;if (age < 0 || age>150){cout << "你输入的年龄有误,默认设置为0." << endl;return m_Age;}m_Age = age;}int getAge(){return m_Age;}void setLower(string lover){m_Lover = lover;}private://姓名 可读可写string m_Name;//年龄 只读int m_Age;//情人 只写string m_Lover;};
int main()
{system("color 1E");Person p;p.setName("唐三");cout << "输入的姓名:" << p.getName()<<endl;//检测数据的有效性p.setAge(1000);cout << "输入的年龄:" << p.getAge()<<endl; //年龄只读p.setLower("小舞"); //情人只能可写return 0;
}
练习案例:
1 设计立方体类
求出立方体的面积和体积。分别用全局函数和成员函数判断两个立方体是否相等

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;/*立方体的类的设计1、创建立方体类2、设计属性3、设计行为 获取立方体面积和体积4、分别利用全局函数和成员函数 判断两个立方体是否相等*/
class Cube
{public:void setL(double l) {m_L = l;}void setW(double w) {m_W = w;}void setH(double h) {m_H = h;}double getL() {return m_L;}double getW() {return m_W;}double getH() {return m_H;}//获取立方体的面积double getArea(){double area;area = 2 * (m_H*m_L + m_H * m_W + m_L * m_W);return area;}//获取立方体的体积double getVolu(){double volume;volume = m_H * m_L * m_W ;return volume;}//利用成员函数判断两个立方体是否相等bool isSameByClass(Cube &c){if (m_L = c.m_L && m_H == c.m_H && m_W == c.m_W){return true;}return false;}private:double m_L, m_W, m_H;};//全局函数判断两个函数是否相等
bool isSameByClasss(Cube &c1, Cube &c2)
{if (c1.getL() == c2.getL() && c1.getH() == c2.getH() && c1.getW() == c2.getW()){return true;}return false;
}int main()
{system("color 1E");Cube c,c1,c2;c.setL(1);c.setW(2);c.setH(3);c1.setL(2);c1.setW(2);c1.setH(2);c2.setL(2);c2.setW(2);c2.setH(3);cout << "立方体的面积:" << c.getArea() << endl;cout << "立方体的体积:" << c.getVolu() << endl;bool gouRet = isSameByClasss(c1, c2);if (gouRet == true){cout << "全局函数的两个立方体是相等的" << endl;}elsecout << "全局函数的两个立方体是不相等的" << endl;bool ret = c1.isSameByClass(c2);if (ret == true){cout << "两个立方体是相等的" << endl;}elsecout << "两个立方体是不相等的" << endl;return 0;
}
2 对象的初始化和清理
- 生活中有些电子产品都有出厂设置
- 每个对象初始设置以及对象销毁前的清理数据的设置
2.1 构造函数和析构函数
对象的初始化和清理是重要的安全问题
- 一个对象或者变量没有初始状态,对其使用后果也是未知的
- 同样,使用完一个对象或变量,没有及时清理也会造成 一定的安全问题
C++利用构造函数和析构函数解决上述问题,这两个函数会被编译器自动调用 ,完成对象初始化和清理工作。若是不提供构造和析构,编译器会提供构造函数和析构函数是空实现的(自己不写,有人写)
- 构造函数:主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动
- 析构函数:作用于对象销毁前自动调用,执行一些清理 工作。
构造函数语法: 类名(){ }
- 1 构造函数,没有返回值也不写void
- 2 函数名称与类明相同
- 3 构造函数可以有参数,因此可以重载
- 4 程序在调用对象的时候会自动调用构造,无需 手动调用,且只调用一次
析构函数语法 :~类名(){ }
- 1 析构函数,没有返回值不写void
- 2 函数名称与类名相同,在名称前面加上符合 ~
- 3 析构函数不可以有参数,因此不能发送重载
- 4 程序在对象销毁前会自动调用析构,无需手动调用,只调用一次
class Person
{
public:Person(){cout << "正在构造函数!! " << endl;}~Person(){cout << "正在析构函数!! " << endl;}
};
void test01()
{Person p;
}
int main()
{test01();return 0;
}

2.2 构造函数的分类及调用
两种分类方式:
-
按照参数分:有参构造和无参构造
Person(){cout << "无参的构造函数调用!! " << endl;}Person(int a){age = a;cout << "有参的构造函数调用!! " << endl;} -
按照类型分:普通构造和拷贝构造
//拷贝构造函数/*定义:若是有张三这个人,然后用李四去克隆张三这个人的属性不过张三本身属性不能改变,加上 const只读*/Person(const Person &p){age = p.age;}
三种调用方式:
-
括号法(一般这个比较好 )
注意:若是无参的函数构造不要写"p1()";这样会被认为是函数的声明
//1、括号法Person p1;//有参构造函数Person p2(10);cout << "p2的年龄为:" << p2.age << endl;//拷贝构造函数Person p3(p2);cout << "p3的年龄为:" << p3.age << endl;

-
显示法
注意:Person(10)若是在左侧,则是匿名对象;执行结束后,系统立马回收匿名对象函数
Person p1; //有参构造函数 Person p2 = Person(10); //拷贝构造函数 Person p3 = Person(p2); -
隐式转换法
Pensor p4=10; //相当于写了Person p4=Person(10) 有参构造 Pensor p5=p3; //拷贝构造
2.3 拷贝构造函数调用时机
C++拷贝构造函数调用时机通常有三种情况
-
使用一个已经创建完毕的对象来初始化一个对象
-
值传递的方式给函数参数传值
void doWork(Person p) { } void test() {Person p; //默认构造函数doWork(p);//拷贝构造函数,给函数的p, } -
以值的方式返回局部对象
Person doWork() {Person p1;return p1; //返回p1的时候,也会产生一个拷贝构造函数。返回会重新生成一个跟p1一样的数据 } void test() {Person p = doWork(); }
2.4 构造函数调用规则
默认情况下,只要创建类,C++编译器至少给应该类添加3个函数
- 默认构造函数(无参,为空)
- 默认析构函数(无参,为空)
- 默认拷贝析构函数,对属性的值进行拷贝
构造函数调用规则如下:
- 如果用户定义有参构造函数,C++不提供默认无参构造,但会提供默认拷贝构造
- 如果用户定义拷贝构造函数,C++不再提供其他构造函数(有参、无参)
2.5 深拷贝与浅拷贝(面试提及)
- 浅拷贝:简单的赋值拷贝(编译器做)-》会导致堆区的内存重复释放

-
深拷贝:在堆区重新申请空间,进行拷贝操作

class Person
{
public:int age;int * Height;//构造函数Person(){cout << "无参的构造函数调用!! " << endl;}Person(int a,int height){age = a;//用new在堆区创建一个对象Height = new int(height);cout << "有参的构造函数调用!! " << endl;}//自己实现拷贝构造函数 解决浅拷贝带来的问题Person(const Person &p){cout << "Person 拷贝构造函数调用" << endl;age = p.age;//Height = p.Height; 编译器默认实现这行代码//在堆区重新申请空间,进行深拷贝Height = new int(*p.Height);}//析构函数~Person(){//释放堆区创建的内存if (Height != NULL){delete Height;Height = NULL;}//作用:析构代码,将堆区开辟数据做释放cout << "正在析构函数!! " << endl;}
};
//调用
void test01()
{//p1走自己的析构,p2也是自己的析构Person p1(18, 180);cout << "p1的年龄为:" << p1.age << " 身高为:" << *p1.Height << endl; //*表示指针的实际化,输出的是一个值,不是地址Person p2(p1);cout << "p2的年龄为:" << p2.age << " 身高为:" << *p2.Height << endl;
}
说明:若是使用指针就会在堆区使用内存空间,p1和p2两个对象,然后两个对象指向同一块内存;delete是释放对象指向的内存,这里用浅拷贝会被释放两次。

2.6 初始化列表
说明:C++提供初始化列表语法,用来初始化属性
语法:构造类名():属性1(值1),属性2(值2) . . . { }
1)传统初始化列表:
class Person
{
public:int m_A;int m_B;int m_C;//传统列表赋初值Person(int a, int b, int c){m_A = a;m_B = b;m_C = c;}
};
void test()
{Person p(10, 20, 30);cout << "m_A = " << p.m_A << endl;cout << "m_A = " << p.m_B << endl;cout << "m_A = " << p.m_C << endl;
}
改进之后的:
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
}

2.7 类对象作为类成员
说明:C++类中的成员可以是另一个类的对象,称为该成员为对象成员。当其他类对象作为本类对象,构造的时候先构造其他类对象,再构造自身对象。析构的时候先释放自身内存 ,再释放其他对象内存。
//创建手机的类
class Phone
{
public:string m_Pname;Phone(string name){m_Pname = name;cout << "正在调用手机类的构造函数" << endl;}~Phone(){cout << "正在调用手机类的析构函数" << 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;}
};
//调用
void test01()
{Person p("张三", "苹果14pro");cout << p.m_Name << "拿着:" << p.m_Phone.m_Pname << "手机" << endl;}

2.8 静态成员
静态成员就是想在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
1)静态成员变量
- 所有对象共享一份数据(若是p1.a=100,若是p2也调用,p2.a=200,则p1.a=200;a是共享的)
- 在编译阶段分配内存
- 类内声明,类外初始化(在类外声明一个类内定义的属性,初始化:int Person::a=100),类外访问不到私有静态成员变量。
- 私有成员变量访问不到
class Person
{
public:static int m_Age;
};
int Person::m_Age = 100;Person p;
//访问方式一:通过对象
cout << p.m_Age << endl; ->100
//访问方式二:通过类名
cout<<Person::m_Age<<endl; ->100
Person p1;
p1.m_Age = 200;
cout << p.m_Age << endl; ->200 //修改了
2)静态成员函数
- 所有对象共享一个函数
- 静态成员函数只能访问静态成员变量,非静态成员变量函数,无法区分到底是那个对象的属性;而静态成员变量所有人共享一份,不属于任何人。
- 私有成员函数访问不到
相关文章:
【类与对象】封装对象的初始化及清理
C面向对象的三大特性:封装、继承、多态。具有相同性质的对象,抽象为类。 文章目录1 封装1.1 封装的意义(一)1.2 封装的意义(二)1.3 struct 和 class区别1.4 成员属性设置为私有练习案例:1 设计…...
【算法】——并查集
作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下🐾 文章目录1.思想2.模板3.应用3.1 合并集合3.2 连通块中点的数量1.思想 并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题…...
Python3,为了无损压缩gif动图,我不得不写了一个压缩神器,真香。
gif动图无损压缩1、引言2、代码实战2.1 模块介绍2.2 安装2.3 代码示例3、总结1、引言 小屌丝:鱼哥, 求助~ 求助~ 求助~ 小鱼:你这是告诉我,重要的事情 说三遍吗? 小屌丝:你可以这么理解。 小鱼:…...
文献阅读 An implementation of the seismic resolution enhancing network based on GAN
题目 An implementation of the seismic resolution enhancing network based on GAN 基于GAN的地震分辨率增强网络的实现 摘要 对于地震数据,本文利用深度学习来学习不同层次的特征并将它们合并以恢复缺失的分辨率。 将GAN网络引入到地震数据处理;对…...
Google员工说出了我不敢说的心里话!
前言:本文来自Beyond的投稿,码农翻身做了修改。今天在Medium上看到一篇文章《The maze is in the mouse》,是一个刚从Google离职的员工写的,揭开了Google内部的各种问题,引发了很多人的共鸣,到目前为止&…...
“御黑行动”进行中,三月重保单位已开放接入!
三月重保在即,对于诸多政企单位来说,正面临着特殊时期的安全保障工作这一重要“大考”。 面对越来越专业且隐匿的攻击,各单位承受着巨大压力,尤其是政府、国企、央企等具有重要地位及广泛社会影响面的单位,其网站及业务…...
taobao.top.oaid.client.decrypt( 端侧OAID解密 )
¥开放平台免费API不需用户授权 解码OAID(Open Addressee ID),返回收件人信息。该接口用于客户端直接查看订单隐私数据,解密数据不经过ISV服务器,且包含风控等安全检测。 公共参数 请求地址: HTTP地址:http://gw.api.ta…...
QT+OpenGL鼠标操作和模型控制
文章目录QTOpenGL鼠标操作和模型控制鼠标拾取理论有点小复杂从鼠标计算射线第 0 步:2D 视口坐标第 1 步:3d归一化设备坐标第 2 步:4d齐次剪辑坐标第 3 步:4d眼(相机)坐标第 4 步:4d 世界坐标代码展示模型控制多模型加载…...
爱奇艺“资产重定价”:首次全年运营盈利是拐点,底层逻辑大改善
长视频行业历时一年有余的降本增效、去肥增瘦,迎来首个全周期圆满收官的玩家。 北京时间2月22日美股盘前,爱奇艺发布2022年Q4及全年财报,Q4 Non-GAAP净利润明显超越预期,且首次实现全年运营盈利。受业绩提振,爱奇艺盘…...
MySQL —— 库的操作
文章目录1. 创建数据库2. 字符集和校验规则3. 数据库的基本操作3.1 查看数据库3.2 显示创建数据库的语句3.3 修改数据库3.4 删除数据库3.5 备份,还原数据库4. 查看数据库的连接情况1. 创建数据库 基本语法: create database if not exists 数据库名 选项…...
修改shell的命令提示符
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 一、命令提示符格式 从虚拟控制台登陆后,或者从桌面环境的终端进入shell后,就可以看见shell的命令提示符,这意味着可以输入命令了。注意ÿ…...
介绍并比较Apache Hive支持的文件格式
Apache Hive 支持几种熟知的Hadoop使用的文件格式,Hive也能加载并查询其他Hadoop组件创建的不同文件格式,如Pig或MapReduce。本文对比Hive不同文件格式,如:TextFile, SequenceFile, RCFile, AVRO, ORC,Parquet,Clouder…...
C语言之文件操作
目录 一、什么是文件? 二、C语言如何操作文件 1.操作方式 2.文件指针 2.1 定义文件指针 2.2文件的打开与关闭 2.3文件的顺序读写 2.3文件的随机读写 总结 一、什么是文件? 在电脑磁盘的上的文件。在程序设计中,分为两种:程序…...
Linux->父子进程初识和进程状态
目录 前言: 1. 父子进程创建 2. 进程状态 R(running)状态: S(sleep)状态: D(disk sleep)状态: T(stopped)状态: X(dead)和Z(zombie)状态: 孤儿进程: 前言: 本篇主要讲解关…...
【Linux学习笔记】5.Linux 用户和用户组管理
前言 本章介绍Linux的用户和用户组管理。 Linux 用户和用户组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。 用户的账号一方面可以…...
茂名市 2021 年高中信息技术学科素养展评
没事干,发一下去年去比赛的题目。 目录 第一题 30分 第二题 30分 第一题 30分 题目: “姐姐,乘除法运算太难了,有什么办法能熟练掌握吗?”今年 读小学四年级的表弟向李红求救。为了提高表弟的运算能力,…...
【软件测试】测试人不躺平,进军高级自动化测试自救,你的不一样结局......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 随着测试从业年龄的…...
win10环境下安装java开发环境安装java
一:环境介绍 安装系统版本:win10 java版本:java SE 17 二:下载Java安装包 官网下载Java安装包:Java Downloads | Oracle 中国 选择需要的Java版本进行下载,如果没有要选择的版本,可以选择最新…...
【华为OD机试模拟题】用 C++ 实现 - 开心消消乐(2023.Q1)
最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…...
opencv图像融合
大家好,我是csdn的博主:lqj_本人 这是我的个人博客主页: lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

