【C++初阶】---类和对象(上)

1.类的定义

1.1类的定义格式

class为定义类的关键字,Data为类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或者成员函数
• 为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加_或者m开头,注意C++中这个并不是强制的,只是⼀些惯例,具体看公司的要求。

#include<iostream>
using namespace std;//类的定义
class Data
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Data d;d.Init(2025, 3, 23);d.Print();return 0;
}

在这里插入图片描述
• C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类。
(需要注意的是struct和class两种类有区别,下面我会提到)

struct Data
{void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};

• 定义在类⾯的成员函数默认为inline。

1.2限定访问符

• C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的⽤⼾使⽤。
public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,以后继承章节才能体现出他们的区别。
访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到}即类结束
class定义成员没有被访问限定符修饰时默认为private,struct默认为public
(这就是两种类的区别)
• ⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public。
在这里插入图片描述

1.3类域

• 类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤::作⽤域操作符指明成员属于哪个类域。
• 类域影响的是编译的查找规则,下⾯程序中Init如果不指定类域Stack,那么编译器就把Init当成全局函数,那么编译时,找不到array等成员的声明/定义在哪⾥,就会报错。指定类域Stack,就是知道Init是成员函数,当前域找不到的array等成员,就会到类域中去查找。

//类域
#include<iostream>
using namespace std;class Stack
{
public:void Init(int n = 4);void Print(){cout << capacity << endl;}
private:int* array;int capacity;int top;
};void Stack::Init(int n)
{array = (int*)malloc(sizeof(int) * n);if (array == nullptr)//C++中的空指针{perror("malloc fail!\n");return;}capacity = n;top = 0;
}int main()
{Stack st;st.Init();st.Print();return 0;
}

在这里插入图片描述

2.实例化

2.1实例化的概念

• ⽤类类型在物理内存中创建对象的过程,称为类实例化出对象。
• 类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,⽤类实例化出对象时,才会分配空间。
⼀个类可以实例化出多个对象,实例化出的对象占⽤实际的物理空间,存储类成员变量。
打个⽐⽅:类实例化出对象就像现实中使⽤建筑设计图建造出房⼦,类就像是设计图,设计图规划了有多少个房间,房间⼤⼩功能等,但是并没有实体的建筑存在,也不能住⼈,⽤设计图修建出房⼦,房⼦才能住⼈。同样类就像设计图⼀样,不能存储数据,实例化出的对象分配物理内存存储数据。
在这里插入图片描述

//实例化
#include<iostream>
using namespace std;class Data
{
public:void Init(int year = 2020, int month = 3, int day = 23){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private://这里只是声明,没有开辟空间int _year;int _month;int _day;
};int main()
{//实例化出d1和d2Data d1;Data d2;d1.Init(2020, 2, 2);d1.Print();d2.Init(2023, 2, 3);d2.Print();return 0;
}

2.2对象的大小

分析一下类对象中哪些成员呢?类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?⾸先函数被编译后是⼀段指令,对象中没办法存储,这些指令存储在⼀个单独的区域(代码段),那么对象中⾮要存储的话,只能是成员函数的指针。再分析⼀下,对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各⾃独⽴的成员变量_year/_month/_day存储各⾃的数据,但是d1和d2的成员函数Init/Print指针却是⼀样的,存储在对象中就浪费了。如果⽤Date实例化100个对象,那么成员函数指针就重复存储100次,太浪费了。
所以对象中只存储成员变量,而成员函数存储在公共代码区中
在这里插入图片描述
而C++规定实例化的对象也要符合内存对齐规则:
内存对⻬规则
• 第⼀个成员在与结构体偏移量为0的地址处。
• 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
• 注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值。
• VS中默认的对⻬数为8
• 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。
• 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。
就拿以下代码举例:

//计算类A的大小
class A
{
public:void Print();void Init(int n = 4);private:char c;int n;int a;
};

存储如下:
在这里插入图片描述

在这里插入图片描述
当类中没有成员变量的时候,对象的大小是多少呢?就拿以下代码来说,类B和类C中都没有成员变量,他们两个类所创造出来的对象的大小是1个字节,之所以给1个字节是为了占位标识对象的存在。

#include<iostream>
using namespace std;class A
{
public:void Print(){cout << _year << endl;}
private:int _year;char _name;int _std;
};class B
{
public:void Print(){cout << "B" << endl;}
};class C
{};int main()
{A a;B b;C c;cout << sizeof(a) << endl;cout << sizeof(b) << endl;cout << sizeof(c) << endl;return 0;
}

在这里插入图片描述

3.this指针

3.1this指针的概念

• Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了⼀个隐含的this指针解决这⾥的问题
• 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。⽐如Date类的Init的真实原型为 :

void Init(Date* const this, int year, int month, int day)

• 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this->_year = year;
• C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显⽰使⽤this指针。
this指针一般存储在内存中的栈区,但一个对象调用成员函数,编译器会把对象的地址(也就是this指针的值)压入栈中。成员函数在执行时,会从栈中获取this指针的值,从而能访问该对象的成员。

//this指针
#include<iostream>
using namespace std;class Data
{
public://可以在函数体内写this,实参和形参部分不能写void Init(int year, int month, int day){this->_year = year;this->_month = month;this->_day = day;}void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}private:int _year;int _month;int _day;
};int main()
{Data d1;Data d2;d1.Init(2023, 3, 23);d1.Print();d2.Init(2025, 1, 4);d2.Print();return 0;
}

在这里插入图片描述
在这里插入图片描述

3.1.1题目练习

我们来判断一下以下两段代码的运行结果是什么?

//代码1
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "A::Print()" << endl;}private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}//代码2
#include<iostream>
using namespace std;class A
{
public:void Print(){cout << "A::Print()" << endl;cout << _a << endl;//不同处}private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}

以上两端代码的运行结果是:代码1正常运行,代码2运行奔溃。
为什么呢?因为我们看到,虽然两端代码的p指针虽然都是空指针,但代码1并没有访问类中的成员变量,所以不存在对空指针进行引用的问题,但代码2想要打印成员变量,这就涉及了对类中的成员变量的访问,也就是代码2的问题是对空指针进行引用操作,导致程序的错误访问。
在这里插入图片描述

4.C语言和C++实现栈Stack对比

C++中数据和函数都放到了类⾥⾯,通过访问限定符进⾏了限制,不能再随意通过对象直接修改数据,这是C++封装的⼀种体现,这个是最重要的变化。这⾥的封装的本质是⼀种更严格规范的管理,避免出现乱访问修改的问题。
• C++中有⼀些相对⽅便的语法,⽐如Init给的缺省参数会⽅便很多,成员函数每次不需要传对象地址,因为this指针隐含的传递了,⽅便了很多,使⽤类型不再需typedef⽤类名就很⽅便
1.封装性:
C语言:使用结构体和函数来实现栈,数据(变量)和操作(函数)是分开的,需要手动传递结构体指针来操作数据,封装性较差。
C++:使用类将数据(成员变量)和操作(成员函数)封装在一起,通过对象来调整成员函数,封装性更好,隐藏了内部实现细节。
2.安全性:
C语言:由于数据和操作分离,用户可能会直接访问和修改结构体中的数据,从而破坏栈的完整性。
C++:可以将成员变量私有(private),只能通过类得到成员函数来访问和修改成员变量,提高了数据的安全性。

C语言实现Stack:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{assert(ps);// 满了, 扩容 if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{assert(ps);return ps->top;
}
int main()
{ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);while (!STEmpty(&s)){printf("%d\n", STTop(&s));STPop(&s);}STDestroy(&s);return 0;
}

C++实现Stack:

#include<iostream>
#include<assert.h>using namespace std;
typedef int STDataType;
class Stack
{
public:// 成员函数 void Init(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}void Push(STDataType x){if (_top == _capacity){int newcapacity = _capacity * 2;STDataType* tmp = (STDataType*)realloc(_a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}_a = tmp;_capacity = newcapacity;}_a[_top++] = x;}void Pop(){assert(_top > 0);--_top;}bool Empty(){return _top == 0;}int Top(){assert(_top > 0);return _a[_top - 1];}void Destroy(){free(_a);_a = nullptr;_top = _capacity = 0;}
private:// 成员变量 STDataType* _a;size_t _capacity;size_t _top;
};
int main()
{Stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);while (!s.Empty()){printf("%d\n", s.Top());s.Pop();}s.Destroy();return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust安装并配置配置vscode编译器

一. 下载rustup-init.exe rust下载网址&#xff1a;Getting started - Rust Programming Language 根据系统&#xff0c;选择适合的exe文件 我选择的的是右边64bit的 打开下载的文件 输入1&#xff0c;回车 二. Visual C 安装 自动下载安装vs 等待安装完毕 三. Rust 安装…

openGl片段着色器的含义

片段着色器的含义及代码中的应用说明&#xff1a; 1. 片段着色器的基本概念 片段着色器&#xff08;Fragment Shader&#xff09;是OpenGL着色器管线中的关键组件&#xff0c;主要用于计算屏幕空间中每个片段&#xff08;对应像素&#xff09;的最终颜色。它是图形渲染流程的…

事务的四大特性(ACID)详解

事务的四大特性&#xff08;ACID&#xff09;详解 在数据库管理系统&#xff08;如 MySQL&#xff09;中&#xff0c;事务&#xff08;Transaction&#xff09; 是指一组要么全部执行、要么全部不执行的数据库操作&#xff0c;通常用于确保数据的完整性和一致性。事务有四大核…

ubuntu设置开机自动运行应用

系统版本&#xff1a;Ubuntu 24.04.1 LTS桌面版 按招网上的资料显示&#xff0c;当前版本主要的实现方式有以下两种&#xff0c; 方式1&#xff1a;通过图形界面的【启动应用程序】设置开机自启动&#xff1b;方式2&#xff1a;配置为服务实现开机自启动。 但是在我的电脑上方…

ECharts各类炫酷图表/3D柱形图

一、前言 最近鸡米花实现了各类的炫酷的图表&#xff0c;有3D柱形图、双边柱形图以及异形柱形图&#xff0c;好了&#xff0c;直接上图&#xff1a; 二、效果图 一个个来吧&#xff0c;下面就是代码啦&#xff0c;注意&#xff0c;一下图表展示的宽高均为800px*300px 三、异形横…

机器人原点丢失后找回原点的解决方案与步骤

机器人原点丢失后找回原点的解决方案与步骤 在机器人运行过程中&#xff0c;原点丢失可能导致定位错误、运动失控等问题&#xff0c;常见于机械臂、AGV&#xff08;自动导引车&#xff09;、3D打印机等设备。以下是针对原点丢失问题的系统性解决方案及详细步骤&#xff0c;涵盖…

HCIP——园区网、VLAN

园区网 园区网搭建核心思路&#xff1a;冗余&#xff08;备份&#xff09;--- 保证其健壮性 1、设备冗余 2、线路冗余 3、网关冗余 4、ups&#xff08;不间断电源&#xff09;冗余—— 能不断电&#xff08;物理层&#xff09; 三层交换机和路由器的选择&#xff1a; 三层交换…

虚拟机(二):Android 篇

虚拟机&#xff08;一&#xff09;&#xff1a;Java 篇 虚拟机&#xff08;二&#xff09;&#xff1a;Android 篇 Dalvik和JVM区别 Dalvik 基于寄存器&#xff0c;而 JVM 基于栈。 基于栈的架构具有更好的可移植性&#xff0c;因为其实现不依赖于物理寄存器基于栈的架构通常指…

Android Token的原理和本地安全存储

Android Token的原理和本地安全存储 前言 在移动应用开发中,Token是实现用户身份验证和授权的重要机制。本文将深入介绍Token的原理,以及在Android平台上如何安全地存储Token,帮助开发者构建可靠的身份验证系统。 基础知识 1. Token概述 1.1 Token的作用 身份验证授权访…

Vue Kubernetes项目 局部布局 下拉菜单

下拉菜单 [el-dropdown] 下拉菜单也比较简单&#xff0c;就是类似于按钮下面来一个下拉菜单。 示例Demo如下&#xff1a; <template><el-dropdown><span class"el-dropdown-link">下拉菜单<i class"el-icon-arrow-down el-icon--right&q…

Android之卡片式滑动

文章目录 前言一、效果图二、实现步骤1.主界面xml2.自定义的viewpage3.卡片接口类4.阴影和缩放变化类5.卡片adapter6.卡片adapter的xml7.style8.CardItem9.activity实现10.指示器drawable 总结 前言 对于这个需求&#xff0c;之前的项目也有做过&#xff0c;但是过于赶项目就没…

(UI自动化测试web端)第二篇:元素定位的方法_css定位之css选择器

看代码里的【find_element_by_css_selector( )】( )里的表达式怎么写&#xff1f; 文章介绍了第三种写法css选择器&#xff0c;你要根据网页中的实际情况来判断自己到底要用哪一种方法来进行元素定位。每种方法都要多练习&#xff0c;全都熟了之后你在工作当中使用起来元素定位…

使用vscode搭建pywebview集成vue项目示例

文章目录 前言环境准备项目源码下载一、项目说明1 目录结构2 前端项目3 后端项目获取python安装包(选择对应版本及系统) 三、调试与生成可执行文件1 本地调试2 打包应用 四、核心代码说明1、package.json2、vite.config.ts设置3、main.py后端入口文件说明 参考文档 前言 本节我…

C stm32f10x LED亮

#include<stm32f10x.h>int main(){#if 0 //APIOA 时钟初始化unsigned int * p(unsigned int*)0x40021018;*p | 0x1<<2;//A0 推挽输出p(unsigned int*)0x40010800;*p *p & ~0xf | 0x1;//A0低电平p(unsigned int*)0x4001080c;*p & ~0x1;#endifRCC->APB2E…

redux ,react-redux,redux-toolkit 简单总结

Redux、React-Redux 和 Redux Toolkit 是协同工作的三个库&#xff0c;各自承担不同角色&#xff0c;相互协同。 Redux&#xff1a;基础底座 底层状态管理库&#xff0c;负责状态存储、Action 派发和 Reducer 执行 ​React-Redux&#xff1a;连接 React 组件与 Redux Store 通…

智能制造:物联网和自动化之间的关系

工业自动化 工业自动化是机器设备或生产过程在不需要人工直接干预的情况下按预期的目标实现测量、操纵等信息处理和过程控制的统称。 在传统的工业生产过程中&#xff0c;很多环节需要人工操作&#xff0c;比如设备调试、生产监控、质量检测等。然而&#xff0c;随着工业自动化…

“自动驾驶背后的数学” 专栏导读

专栏链接&#xff1a; 自动驾驶背后的数学 专栏以“自动驾驶背后的数学”为主题&#xff0c;从基础到深入&#xff0c;再到实际应用和未来展望&#xff0c;全面解析自动驾驶技术中的数学原理。开篇用基础数学工具搭建自动驾驶的整体框架&#xff0c;吸引儿童培养兴趣&#xff0…

集成学习(下):Stacking集成方法

一、Stacking的元学习革命 1.1 概念 Stacking&#xff08;堆叠法&#xff09; 是一种集成学习技术&#xff0c;通过组合多个基学习器&#xff08;base learner&#xff09;的预测结果&#xff0c;并利用一个元模型&#xff08;meta-model&#xff09;进行二次训练&#xff0c…

Dubbo 全面解析:从 RPC 核心到服务治理实践

一、分布式系统与 RPC 框架概述 在当今互联网时代&#xff0c;随着业务规模的不断扩大&#xff0c;单体架构已经无法满足高并发、高可用的需求&#xff0c;分布式系统架构成为主流选择。而在分布式系统中&#xff0c;远程服务调用&#xff08;Remote Procedure Call&#xff0…

vmware虚拟机突然连不上网

1.一般是自己的主机把服务给关掉了&#xff0c;右击我的电脑&#xff0c;然后找到管理->服务&#xff0c;确保下面虚拟机的网络服务是否打开 Vmware虚拟机突然连接不上网络【方案集合】_vmware虚拟机连不上网-CSDN博客 2.识别到无效网络 控制面板->网络和共享中心&…