C++基础之类、对象一(类的定义,作用域、this指针)
目录
面向对象的编程
类的引入
简介
类的定义
简介
访问限定符
命名规则
封装
简介
类的作用域
类的大小及存储模型
this指针
简介
面向对象的编程
C++与C语言不同,C++是面向对象的编程,那么什么是面向对象的编程呢?
C语言编程,规定了编程的每一步指令,程序从上而下一步一步按照指令,最终达到想要的结果,而面向对象是另一种思路,将一件事情拆分成不同的对象,任务需要依靠对象之间的交互完成,也就是说关注模块和模块之间的关系。
类的引入
简介
类是C++中重要的概念,从C语言的结构体升级而来,C语言的结构体只能定义变量,C++中结构体不仅可以定义变量还能定义函数(成员变量/成员属性,成员函数/成员方法)
typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}void Push(const DataType& data){// 扩容_array[_size] = data;++_size;}DataType Top(){return _array[_size - 1];}void Destroy(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}DataType* _array;size_t _capacity;size_t _size;};int main(){Stack s;s.Init(10);s.Push(1);s.Push(2);s.Push(3);cout << s.Top() << endl;s.Destroy();return 0;}
类的定义
C++中用class作为关键字定义类,其结构如下:
class classname
{//类体//成员变量(成员属性)//成员函数(成员方法)
};
访问限定符
C++中设置了访问限定符,其作用是设置类体的属性,访问限定符作用域从当前限定符开始直到下个访问限定符出现结束,如果没有访问限定符则直到类结束;
1、public 修饰的类体,可以直接被外部访问;
2、protected(保护)与private(私有)修饰的类体有同样的特征不允许被外部访问;
3、struct与class在默认的访问限定符不同,struct为了兼容c语言,默认的是public,class默认的是private。
命名规则
先看一下下面代码
class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};
void init(int year, int month, int day){year = year;month = month;day = day;}
这段代码阅读起来很不方便,形参与类中的成员变量无法区别,为了更好的阅读,在成员变量命名时可以加以区分;
class Date
{
private:int _year;int _month;int _day;
public:void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};
封装
简介
C++中存在多种特性,面向对象的最主要的是封装,继承,多态;
类和对象的阶段,主要是封装的特性,那么什么是封装呢?
简单的说,封装是一种管理行为,将程序的属性与方法结合在一起,隐藏对象的属性和细节,仅保留对外接口和对象进行交互,封装的特性在C++的类中体现的很明显;
class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};int main()
{Date s;s.print();system("pause");return 0;
}
上面的代码中,成员变量无法通过外部进行修改,只能通过init函数进行修改;
类的大小及存储模型
先看下面的代码:
class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date s;printf("类的大小:%d\n", sizeof(s));system("pause");return 0;
}
上面这段代码的结果为12。为什么是12而不是20(包含两个函数的指针),这由类的存储模型决定的。
类的存储模型
内存通常分为栈区,堆区,静态区,常量区等,(栈区的空间非常小)为了节省空间,编译器会将成员函数放在常量区(代码段)中,使用时寻找函数。
this指针
先看下面的代码及运行结果
class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);d1.print();d2.print();system("pause");return 0;
}
成员函数存储在常量区,那为什么d1和d2调用时会打印出不同的结果呢?
这是因为类中的函数有一个隐藏的参数this指针。
void thisprint(Date *this)//this指针隐藏在类的函数中,不能手写,编译器自动完成
那么this指针又是什么呢?
class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}void thisprint(){printf("this指针:%p\n", this);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);printf("d1的地址: %p\n", &d1);d1.thisprint();printf("d2的地址: %p\n", &d2);d2.thisprint();system("pause");return 0;
}
通过上面代码的结果,this指针就是类的地址,那么可以由以下结论;
void print(){printf("%d-%d-%d\n", this->_year, this->_month, this->_day);}
//类能通过常量区的成员函数打印值,是通过指针调用完成的。
为了保护this指针的值不被修改,this指针会用const修饰,写成const int * this(指针指向的值无法被修改 int * const this指针指向的变量不能被修改);
this指针也是存在栈区中,其作用域与生命周期随着函数的调用而产生,随着函数的销毁而消失,VS下通常优化在寄存器ecx中;
this 指针可以为空吗?
//先看下这段代码
class A
{
public:void Print(){std::cout << "Print()" << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();system("pause");return 0;
}
//结构体的指针为nullptr,this指针为nullptr,在调用函数时Print函数从常量区中调用,与this指针无关,所以该程序可以正常运行;
//再看下面这段代码
class A
{
public:void PrintA(){std::cout << _a << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}
//虽然PrintA函数被成功调用,但是因为p指向nullptr,所以_a是无法读取内存的,因此运行时程序会崩溃
类的作用域
类的作用域是{}中的部分,但是它只是虚拟的,这是因为类类似于图纸;
class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};namespace date
{int _year = 2023;int _month = 5;int _day = 1;
}int main()
{Date s;/*s.print();*/printf("%d-%d-%d\n", date::_year, date::_month, date::_day);printf("%d-%d-%d\n", Date::_year, Date::_month, Date::_day);//该语句无法通过编译system("pause");return 0;
}
上面的代码中,命名空间的变量可以通过作用域运算符::来找到对应的变量,但是类中定义的变量不能通过,其原因就是类没有被真实创建,类定义的只是图纸。
事实上不光是成员属性不能使用作用域运算符,成员方法也不行,这是因为this指针,虽然类中创建了成员函数,但是类没有被创建,没有this指针,所以运行崩溃。
成员函数的创建
定义成员函数时,如果将成员函数都放在类的内部,那么阅读起来会非常麻烦,通常只在类中声明,在外部定义;
class A
{
public:void PrintA();
private:int _a=10;
};void A:: PrintA()
{std::cout << _a << std::endl;
}int main()
{A _a;_a.PrintA();system("pause");return 0;
}
相关文章:

C++基础之类、对象一(类的定义,作用域、this指针)
目录 面向对象的编程 类的引入 简介 类的定义 简介 访问限定符 命名规则 封装 简介 类的作用域 类的大小及存储模型 this指针 简介 面向对象的编程 C与C语言不同,C是面向对象的编程,那么什么是面向对象的编程呢? C语言编程,规定…...

javaScript---设计模式-封装与对象
目录 1、封装对象时的设计模式 2、基本结构与应用示例 2.1 工厂模式 2.2 建造者模式 2.3 单例模式 封装的目的:①定义变量不会污染外部;②能作为一个模块调用;③遵循开闭原则。 好的封装(不可见、留接口):①…...

【消息中间件】kafka高性能设计之内存池
文章目录 前言实现创建内存池分配内存释放内存 总结 前言 Kafka的内存池是一个用于管理内存分配的缓存区域。它通过在内存上保留一块固定大小的内存池,用于分配消息缓存、批处理缓存等对象,以减少频繁调用内存分配函数的开销。 Kafka内存池的实现利用了…...
创建型模式——单例(singleton)
1. 模式说明 单例模式保证类只有一个实例;创建一个对象,当你创建第二个对象的时候,此时你获取到的是已经创建过的对象,而不是一个新的对象; 1.1 使用场景 共享资源的访问权限;任务的管理类;数…...

算法:迷宫问题
描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或…...

聊聊并发编程的12种业务场景
前言 并发编程是一项非常重要的技术,无论在面试,还是工作中出现的频率非常高。 并发编程说白了就是多线程编程,但多线程一定比单线程效率更高? 答:不一定,要看具体业务场景。 毕竟如果使用了多线程&…...

MySQL执行顺序
MySQL执行顺序 MySQL语句的执行顺序也是在面试过程中经常问到的问题,并且熟悉执行顺序也有助于SQL语句的编写。 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序如下: FROM ON JOIN WHERE GROUP BY # (开始使用别名) SUM # SUM等…...

引领真无线耳机未来趋势,NANK南卡OE骨传导真无线耳机惊艳亮相
传统的蓝牙耳机存在很多问题,例如续航时间短、长期佩戴耳朵会不舒服,甚至影响听力等等。为了解决这些问题,在骨传导领域深耕十多年的南卡品牌推出了这款真无线骨传导耳机——NANK南卡 OE。 NANK南卡OE即将正式上线,这一消息一经宣…...

5款写作神器,帮助你写出5w+爆款文案,好用到哭
我不允许还有文案小白、新手博主不知道这5款写作利器! 每次一写文案就头秃的新媒体工作者,赶紧看过来吧!这5款好用到爆的写作神器,喝一杯咖啡的时间就能完成写作。 我和同事都是用它们,出了很多的爆款,现…...

相交链表问题
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&…...
[ubuntu] ax200网卡虚接,导致系统根目录占满而无法进入系统的奇葩问题
20230508,我像往常一样,打开电脑发现根目录满了,报警了,所以按照网上的教程,清理了一下根目录的文件,没想到背后是网卡问题… 文章目录 1.进入终端模式2.查看占用情况3.清理系统log文件3.1 清理/var/log/syslog3.2 清…...
本地字体库的引入方法
本地字体库是指在计算机系统中存储的一组字体文件,通常包含多种字体格式,如TTF、OTF、WOFF等。引入本地字体库可以让用户在使用计算机时可以选择不同的字体,从而提高用户的使用体验。 本地字体库的引入方式有多种,其中比较常用的是…...

7种优秀的导航菜单设计总结
导航是应用程序界面中最常见的模块之一,在链接应用程序中起着每个页面的作用。 不同的设计需求和业务目标决定了导航的设计因品而异,移动设备的尺寸远小于计算机。因此,在设计移动终端导航时,应考虑更全面,以确保简单…...
Problem E. 矩阵游戏 (2023年ccpc河南省赛)
原题链接: https://codeforces.com/gym/104354 题意: 有一个n*m的矩阵,只有三种字符:0,1和?。从[1,1]走到[n,m],每次只能向下走或者向下走。当走到1的时候得一分,走到0的时候不得分,走到?的时候可以将他…...

数字孪生模型构建理论及应用
源自:计算机集成制造系统 作者:陶飞 张贺 戚庆林 徐 俊 孙铮 胡天亮 刘晓军 刘庭煜 关俊涛 陈畅宇 孟凡伟 张辰源 李志远 魏永利 朱铭浩 肖斌 摘 要 数字孪生作为实现数字化转型和促进智能化升级的重要使能途径,一直备受各…...
Vue面试题:30道含答案和代码示例的练习题
Vue中的双向数据绑定是怎么实现的? 双向数据绑定通过使用v-model指令实现。v-model指令会在表单元素上创建一个监听器,在用户输入时实时更新Vue实例的数据,并且在Vue实例数据变化时更新表单元素的值。 如何在Vue中定义一个方法?…...
2023-05-09 LeetCode每日一题(有效时间的数目)
2023-05-09每日一题 一、题目编号 2437. 有效时间的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 5 的字符串 time ,表示一个电子时钟当前的时间,格式为 “hh:mm” 。最早 可能的时间是 “00:00” ,最晚 可能的时间…...

第三节课 Linux文件权限
目录 文件属性详解 权限修改 文件所有者与属组修改 文件默认权限修改 Linux是多人多任务的操作系统,因此可能常常会有多人使用一台机器, 为了考虑每个人的隐私、方便用户合作,每个文件都有三类用户,权限是基于这三类用户设定的…...
开发STC89C51系列单片机需要的单片机技术
端口操作:控制单片机的输入输出端口,与外界进行通信。中断优先级:当多个中断同时发生时,确定哪个中断优先级更高,优先响应。时钟模块:控制单片机的时钟,可以精确计时。PWM技术:实现模…...
分布式键值存储是什么?(分布式键值存储大值)
文章目录 什么是分布式键值存储?分布式键值存储“大值”指什么? 什么是分布式键值存储? 分布式键值存储是一种分布式数据存储系统,它将数据存储为键值对的形式,并将这些键值对分散在多个节点上。每个节点都可以独立地…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...