21天学会C++:Day9----初识类与对象
· CSDN的uu们,大家好。这里是C++入门的第九讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题
目录
1. 面向过程与面向对象
2. 类的定义
3. 类中的访问限定符
3.1 访问限定符的作用
4. 对象的实例化以及对象的大小
5. this指针
5.1 this指针的引入
5.2 VS中this指针的优化
5.3 考验你对this指针理解的两道题
1. 面向过程与面向对象
我们之前学习的C语言是面向过程的语言,而我们正在学习的C++是面向对象的语言(OOP语言)。之前提到过,C++是对C语言的补充和改进。那么为什么C++要引入面向对象的概念呢?面向对象又比面向过程好在哪里呢?
面向过程,关注的是解决问题的步骤,将每一个功能都抽象出一个个具体的函数,然后逐步解决问题。
例如:我们在家洗衣服,站在面向过程的角度来看是这个样子:
通过一个一个的步骤来解决问题。在编程中就是通过一个一个的函数来实现。
面向对象:在解决问题的过程中,面向对象的思想是将解决该问题中的事物看作一个一个的对象,对象之间各司其职,达到解决问题的目的。
例如:在洗衣的过程中,人这个对象只需要将衣服放进洗衣机,等洗衣机洗好之后取出来即可。不需要关注洗衣机是怎么洗衣服的。
现在来分析面向对象与面向过程的优缺点还是太早了。我们只要有一个大致印象,面向对象比面向过程更加高级,面向对象能够更加方便的将问题模块化, 更好的解决问题。但是相比于面向对象,面向过程的代码执行效率较高。
2. 类的定义
我们知道C++是兼容C语言的,C语言的结构体里面是不能定义函数的。但是C++的结构体里面是可以定义函数的,因为C++将结构体升级成为了类,像这样:
struct A
{int _a;void func(){cout << "func" << endl;}
};int main()
{struct A a1;return 0;
}
C++将结构体升级成为了类,那么结构体的名字就是类型的名字,因此在C++中定义结构体是不需要加上struct的。
struct A
{int _a;void func(){cout << "func" << endl;}
};int main()
{struct A a1;A a1; //c++不用加structreturn 0;
}
在C++里面更喜欢用class代替struct来定义一个类,于是我们顺理成章地推导出了class定义类的方法:
class 类名
{
// 类的主体,包括成员变量和成员函数
};
注意:分号不能少。
// 定义一个类
class B
{int _b;void func(){cout << "func" << endl;}
};
上面的代码我们定义了一个类 B。 类中的变量(_b),叫做成员变量,类中定义的函数(func) 叫做成员函数 或者方法。
C++规定:在类中的定义的函数,会被自动地视为inline函数,但是他最后是不是内联函数,还是取决于编译器。
注意:是在类中定义的函数,如果你是在类内声明,类外定义,不会被视为内联函数。
struct B
{int _b;void func() //函数的声明定义均在类里面{int a = 10;}void func(int a);
};void B::func(int a)
{int b = 10;
}int main()
{B b;b.func();b.func(1);return 0;
}
上面的代码,func() 函数就是在类内定义的函数, 而func(int a) 则是在类外定义的函数,通过调试观察汇编代码,我们可以看到func()已经是一个内联函数了。
关于内联函数的细节:21天学会C++:Day6----内联函数_姬如祎的博客-CSDN博客
这里还有一个要注意的点:类中函数类外定义的写法,需要加上类名和域作用限定符,告诉编译器这是这个类里面的函数的实现。不然可能会与全局域的函数冲突。
class中的所有成员变量都在其所在的那个类域里面,这样做是理所应当的。
3. 类中的访问限定符
我们用struct定义了一个类 A,用class定义了一个类 B,创建一个变量之后。访问其各自的成员变量。发现struct定义的类可以直接访问,但是class定义的类不能直接访问成员变量。这是为啥呢?
struct A
{int _a;void func(){cout << "func" << endl;}
};class B
{int _b;void func(){cout << "func" << endl;}
};int main()
{A a;a._a = 10;B b;b._b = 10;return 0;
}
这是因为C++中每一个类中的成员都会受到访问限定符的限制。我们来看看C++中的访问限定符有哪些:
其中public表示类成员在类内类外都可以访问;protected,private均是类成员在类内可以访问,在类外不可以访问。protected 与 private之间的区别需要我们学到继承的时候再讲。
于是我们就可以得出结论,在没有写访问限定符的时候,struct定义的类默认访问限定符是public;class定义的类默认访问限定符是private。
访问权限的作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。没有下一个访问限定符就是到类的结束位置。
3.1 访问限定符的作用
这里需要uu们回忆一下我们在使用C语言实现的数据结构,无论哪一个都行。我们就拿栈来说吧,我们当时定义的栈是这样的:
C语言数据结构初阶(5)----栈_姬如祎的博客-CSDN博客
//栈的数据类型
typedef int STDataType;
//栈的结构体,类比顺序表
typedef struct Stack
{STDataType* a; //栈的顺序存储的数组int top; //栈的top元素int capacity; //数组的容量
} ST;
这其中有一个top变量,我们在在实现栈的时候,提到过top可以指向栈顶元素或者栈顶元素的下一个位置,这取决于设计者的实现方式。
因为C语言结构体中的数据是公开的,于是,就会有程序员在访问栈顶的元素时写出这样的代码:
int main
{ST s;s.a[top];
}
是的,他不调用你实现的访问栈顶元素的函数,而是直接通过你的底层,直接访问数据。如果恰巧你实现的栈关于top的定义是实现方式2,碰巧他还是一个脾气暴躁的程序员,当他看到访问top的时候出现了随机值,他可能会直接破口大骂,这是谁写的 laji 代码。C语言没有常见数据结构的库也有一部分原因是这个吧。
没有访问限定符的限制,用户可以直接访问并修改任意数据,造成意料之外的结果,甚至导致程序崩溃。而有了访问限定符就能很好的解决这些问题。
我们只需要将stack的底层数据用private修饰就能很好的解决这些问题。同时将对应操作的函数用public修饰,提供对外接口供用户使用。
class Stack
{
public:void StackInit(){//}void StackPush(int val){//}//等等private:int* _a;int _capacity;int top;
};
这就是封装的具体表现了。
封装是面向对象的三大特性之一,另外两个是继承和多态。继承和多态后面讲解。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。 封装本质上是一种管理,让用户更方便使用类。
4. 对象的实例化以及对象的大小
思考这样一个问题:你定义好了一个类,他是否在内存中占有空间呢?
答案显然是否定的,因为类是对象的描述,类在定义好时并不分配内存空间,只有在类实例化出对象之后,这个对象占有空间。我们完全可以把类当作一张图纸,而对象就是根据图纸生产出来的商品。
class A
{
public:void func(){cout << "func" << endl;}private:int _a;int* _p;
};int main()
{A a;return 0;
}
那么我们应该如何计算对象的大小呢?拿上面的代码来说,sizeof(a)结果是什么呢?
(这里写sizeof(A) 也行,根据对象能算出大小,根据类肯定也行撒,类比图纸与商品)
在32位机器下,结果是8。对象大小的计算方式和结构体大小的计算是一样的,都遵循内存对齐。
但是,你可能会问,成员函数存在哪里呢?对象里面没有成员函数是怎么调用的呢?
在回答这些问题之前,我们先来思考。不同的对象调用类中的函数是调用的同一个吗?没错调用的就是同一个。
既然所有的对象都会调用相同的成员函数,那么为什么还要浪费空间在每个对象里面存一份函数的地址呢,因此类的成员函数是存在公共代码段的,源文件编译的时候编译器会找到函数的地址,我们不必关心。
既然对象里面只存储成员变量,那要是我定义的类里面没有成员变量,那他还会有空间吗?
我们看到结果是1,如果没有成员变量就没有空间的话,我们应该用什么来表征这个对象的存在呢?因此即使没有成员变量的类,实例化出的对象也是有空间的,至于具体的大小,依编译器而定。
5. this指针
5.1 this指针的引入
我们创建了一个Date 类,类的成员变量用来存储年月日。InitiDate函数用来初始化一个Date对象的日期,ShowDate用来打印Date对象表示的日期。
class Date
{
public:void InitDate(int year, int month, int day){_year = year;_month = month;_day = day;}void ShowDate(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;};int main()
{Date d1;d1.InitDate(2004, 01, 01);d1.ShowDate();Date d2;d2.InitDate(2008, 01, 01);d2.ShowDate();
}
我们上一个小节讲到了一个类实例化出来一个对象就会开辟一份属于自己空间,那么上述代码中的d1,d2是两个不同的对象,也就各自拥有一份空间来存储各自表示的日期。但是类的成员函数只有一份,他是怎么做到不同的对象调用同一个函数时,找到不同空间中的数据(d1调用ShowDate打印的是d1中存储的信息,d2调用ShowDate打印的是d2中存储的信息)的呢?
这就得讲讲我们的this指针了,C++语法规定,对于非静态成员函数(没有加static修饰的成员函数),编译器会对成员函数做处理:在普通成员函数中加了一个隐藏的指针参数,让这个指针指向当前对象( 正在调用这个函数的对象,d1调用ShowDate,this指向的就是d1这个对象)。需要注意的是this指针不能在形参和实参显示传递,但可以在函数内部显示使用。
例如,ShowDate函数可以这样写:
void ShowDate()
{cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}
现在我们就能理解为什么同一个函数能访问不同的空间了吧,因为隐藏传递了一个this指针,打印_year等变量,实际上是通过传递过来的this指针找到调用该函数的对象中的数据。因此才能做到一个函数访问两块空间。
那这里我就要问一个问题了,各位uu觉得this指针存储在哪里呢?
A:对象 B:栈 C:堆
答案:B。
A:如果this指针存在对象中,那么我们刚才计算对象大小的时候并没有计算this指针哇,因此排除a。
我们再来看看this的定义嘛,this是对象这个实参传递过来的,那么this就是形参撒,uu们形参当然是存在栈中的撒。因此this就是存在栈中的!!!
5.2 VS中this指针的优化
我们来看看VS对this指针的优化:我们通过反汇编来看看this指针的传递
我们可以看到,VS中直接将this指针存在了寄存器中,我们都知道寄存器的读写速度是非常快的,在类的内部,我们需要大量访问成员变量。而访问成员变量本质上是通过this指针来访问的。因此将他存储到ecx寄存器中能够提高访问的效率。
5.3 考验你对this指针理解的两道题
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}
// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->PrintA();return 0;
}
我们看到这两道题都是通过一个空对象去调用函数,区别是在函数中是否访问对象中的成员变量。
答案:1:运行正常
2:运行崩溃
在调用类成员函数的时候,会隐士传递this指针,都传递的是一个空指针,题目一并没有对this指针解引用,但是题目二确尝试解引用当问成员变量。因为操作成员变量的本质都是通过this指针,因此题目二会发生空指针的解引用,引起程序崩溃。
相关文章:
21天学会C++:Day9----初识类与对象
CSDN的uu们,大家好。这里是C入门的第九讲。 座右铭:前路坎坷,披荆斩棘,扶摇直上。 博客主页: 姬如祎 收录专栏:C专题 目录 1. 面向过程与面向对象 2. 类的定义 3. 类中的访问限定符 3.1 访问限定符的…...
【深度学习】 Python 和 NumPy 系列教程(十七):Matplotlib详解:2、3d绘图类型(3)3D条形图(3D Bar Plot)
目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 线框图 2. 3D散点图 3. 3D条形图(3D Bar Plot) 一、前言 Python是一种高级编程语言,由Guido van Rossum于1991年创建。它以简洁、易读…...
基于Spring Boot+vue的酒店管理系统
文章目录 项目介绍主要功能截图:前台后台部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring Boot+vue的酒店管理…...
Python 通过threading模块实现多线程
视频版教程 Python3零基础7天入门实战视频教程 我们可以使用threading模块的Thread类的构造器来创建线程 def _ init _(self, groupNone, targetNone, nameNone, args(), kwargsNone, *, daemonNone): 上面的构造器涉及如下几个参数。 group:指定该线程所属的线程组。目前该…...
用一个RecyclerView实现二级评论
先上个效果图(没有UI,将就看吧),写代码的整个过程花了4个小时左右,相比当初自己开发需求已经快了很多了哈。 给产品估个两天时间,摸一天半的鱼不过分吧(手动斜眼) 需求拆分 这种大家…...
音视频 SDL简介
一、SDL简介 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Win…...
7.前端·新建子模块与开发(自动生成)
文章目录 学习地址视频笔记自动代码生成模式开发增删改查功能调试功能权限分配 脚本实现权限分配 学习地址 https://www.bilibili.com/video/BV13g411Y7GS/?p15&spm_id_frompageDriver&vd_sourceed09a620bf87401694f763818a31c91e 视频笔记 自动代码生成模式开发 …...
Linux 创建目录
语法:mkdir xxx Linux路径 在当前目录下创建文件夹 在/目录下创建文件夹 如果想要一次性创建多个层级的目录,如下图 会报错,因为上级目录test并不存在,所以无法创建test目录 可以通过-p选项,将一整个链条都创建完成…...
【DIY小记】修复Win10启动出现蓝屏0xc0000185错误的一些方法
近些日子想到自己尘封已久的笔记本电脑没有开机了,很多软件驱动之类的没有更新,就打算把电脑开起来做一轮批量升级。但开电脑的时候很久没有进入Win10桌面,等了很长一段时间蓝屏提示0xc0000185错误,说系统需要恢复。经历了一番折腾…...
Linux 下的 10 个 PDF 软件
本文[1]是我们正在进行的有关 Linux 顶级工具系列的延续,在本系列中,我们将向您介绍最著名的 Linux 系统开源工具。 随着互联网上越来越多地使用可移植文档格式 (PDF) 文件来获取在线书籍和其他相关文档,拥有 PDF 查看器/阅读器对于桌面 Linu…...
浅谈redis分布式锁
浅谈redis分布式锁 分布式锁介绍 分布式锁,顾名思义,分布式系统中的锁,当多个进程不在同一个系统中时,用分布式锁控制各个进程对共享资源的访问,通过互斥来保持一致性。 使用场景:电商中某商品的秒杀活动…...
【Python保姆级教程】List容器
文章目录 前言一、列表是什么二、列表的定义2.1 有初始值2.2 空列表使用方括号创建空列表使用list()函数创建空列表 三、list列表常用操作3.1 添加元素3.2 删除元素3.3 修改元素3.4 列表长度 四、遍历操作4.1 使用for循环4.2 使用while循环和索引 总结 前言 Python是一种广泛使…...
微服务保护-授权规则
个人名片: 博主:酒徒ᝰ. 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来。 本篇励志:三人行,必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》,SpringCloud…...
v-if失效原因
一般v-if失效都是和绑定变量有关,我所知道的一般有两种 1.绑定的变量为String类型或者其他类型 就是返回的变量类型与所需要的布尔类型不匹配。 <template><div><div id"container" ref"container" v-iftype></div>&l…...
Chrome 基于 Wappalyzer 查看网站所用的前端技术栈
1. 找到谷歌商店 https://chrome.google.com/webstore/search/wappalyzer?utm_sourceext_app_menu 2. 搜索 Wappalyzer 3. 添加至Chrome 4. 使用 插件 比如打开 https://www.bilibili.com/ 就可以看到其所以用的前端技术栈了...
python的装饰器
作用:在不改变原来函数的代码情况下,进行修改,或者增加函数的功能装饰器本质上就是一个闭包雏形:def wrapper(fn): wrapper: 装饰器 , fn: 目标函数def inner():# 在目标函数执行前的一些动作fn()# 在目标函数执行后的一些动作return inner #千万别加(),这里是返回一…...
P2P协议的传输艺术
TP 采用两个 TCP 连接来传输一个文件。 控制连接:服务器以被动的方式,打开众所周知用于 FTP 的端口 21,客户端则主动发起连接。该连接将命令从客户端传给服务器,并传回服务器的应答。常用的命令有:list——获取文件目…...
辅助驾驶功能开发-功能规范篇(21)-4-XP行泊一体方案功能规范
XPilot Parking 自动泊车系统 • 超级自动泊车辅助(Super AutoParking Assist)、语音控制泊车辅助(Autoparking with Speech) - 产品定义 超级自动泊车辅助是⼀个增强的自动泊车辅助系统。在超级自动泊车辅助系统中,识别车位将会变得实时可见, 并且不可泊入的⻋位也将…...
家政服务小程序上门服务小程序预约上门服务维修保洁上门服务在线派单技师入口
套餐一:源码=1500元 套餐二:全包服务 包服务器+域名+认证小程序+搭建+售后=2000元 主要功能: 1、服务商入驻 支持个人或企业入驻成为平台服务商; 2、发布商品 入驻服务商后,可以发布服务商品,用户可以在线下单,预约服务; 3、发布需求 用户可以发布一口价或竞价需求…...
LeetCode精选100题-【3数之和】-2
这里写自定义目录标题 解法1:解法2: 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不…...
springboot集成mybatis-plus
一、在spring boot中配置mybatis-plus 1、创建一个spring boot项目,注意勾选mysql 2、在pom.xml文件中添加mybatis-plus的依赖包 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0&qu…...
再想一想GPT
一 前言 花了大概两天时间看完《这就是ChatGPT》,触动还是挺大的,让我静下来,认真地想一想,是否真正理解了ChatGPT,又能给我们以什么样的启发。 二 思考 在工作和生活中,使用ChatGPT或文心一言,…...
Blazor前后端框架Known-V1.2.15
V1.2.15 Known是基于C#和Blazor开发的前后端分离快速开发框架,开箱即用,跨平台,一处代码,多处运行。 Gitee: https://gitee.com/known/KnownGithub:https://github.com/known/Known 概述 基于C#和Blazo…...
Tomcat 的部署和优化
目录 1、什么是Tomcat 1.1、静态页面的选择 2、Tomcat是怎么运行的 3、安装jdk & 部署jdk环境 & Tomcat 安装 1、安装jdk 2、配置jdk环境变量 3、tomcat安装 4、Tomcat启动 5.优化tomcat启动速度 6.Tomcat的主要命令 7.Tomcat 配置虚拟主机 8.Tomca…...
后端中间件安装与启动(Redis、Nginx、Nacos、Kafka)
后端中间件安装与启动 RedisNginxNacosKafka Redis 1.打开cmd终端,进入redis文件目录 2.输入redis-server.exe redis.windows.conf即可启动,不能关闭cmd窗口 (端口配置方式:redis目录下的redis.windows.conf配置文件,…...
【电子元件】常用电子元器件的识别之电阻器
目录 前言1. 电阻器的识别1.1 普通电阻器的识别1. 普通电阻器的识别色环电阻器绕线电阻器水泥电阻器贴片电阻器网络电阻器(排阻)保险电阻器精密电阻器2. 电阻器的符号3. 普通电阻器的主要参数标称阻值和允许误差额定功率最高工作电压温度系数1.2 电位器的识别1. 电位器的识别…...
指针和数组笔试题讲解(2)
🐵本篇文章将会对上篇一维数组笔试题的剩余部分和二维数组的笔试题进行讲解 一、一维数组 1>试题部分(一)✏️ char* p "abcdef";printf("%zd\n", sizeof(p)); printf("%zd\n", sizeof(p 1)); printf("%zd\n", sizeo…...
MapReduce YARN 的部署
1、部署说明 Hadoop HDFS分布式文件系统,我们会启动: NameNode进程作为管理节点DataNode进程作为工作节点SecondaryNamenode作为辅助 同理,Hadoop YARN分布式资源调度,会启动:ResourceManager进程作为管理节点NodeM…...
vue 引入zTree
下载js包解压后找个地方放文件夹内 引入 import "/common/zTree/js/jquery-1.4.4.min" import "/common/zTree/js/jquery.ztree.core.min.js" import "/common/zTree/js/jquery.ztree.excheck.min.js" import "/common/zTree/css/metroSt…...
链队列的基本操作(带头结点,不带头结点)
结构体 typedef struct linknode{int data;struct linknode* next;后继指针 }linknode; typedef struct {linknode* front, * rear;//队头队尾指针 }linkquene; 初始化队列(带头结点) int initquene(linkquene* q)//初始化队列 {q->front q->r…...
建筑工程网签合同周末可以签吗/seo是什么
本文已迁移至:https://blog.csdn.net/COCO56/article/details/89382093 原标题:VS各版本下载与密钥(从2008到2017),VS老版本在官网如何下载(解决下载老版本时提示抱歉,我们找不到适合您的下载内容的问题&a…...
酒店网站html模板/网络销售靠谱吗
1.创建文件myrule 2.编写myrule内容 package com.myrule;Configuration public class MySelfRule {Beanpublic IRule myRule(){return new RandomRule(); //随机的方法} }3.在主启动类中加入这个注解 CLOUD-PAYMENT-SERVICE为服务名称 configuration为刚才我们写的类 Ribbon…...
上海设计网站公司/百度云超级会员试用1天
今天小编又要为大家推荐一款很特别的软件了,这款软件不管是玩法还是画面都没有办法可以挑剔,一起来看看吧!编程一点通APP是一个免费的,能够让你在手机上学习编程知识的一款手机软件,这款软件能够让你在手机上对各种编程…...
建设农村信息网站/哪家公司做seo
Python随机边缘填充:让你的图像变得更完美 在处理图像时,很多时候需要对图像进行边缘填充。那么问题来了,如何才能让图像的边缘填充看起来更自然、更完美呢?Python中有很多方法可以实现这个目的,本文将介绍一种让你的图像边缘填充看起来更自然的方法。 通常情况下,我们…...
朋友让你做网站如何拒绝/seo优化首页
一维数组的内存分析 二维数组的内存分析 2. 3....
如何做网站的cdn/整合营销方案案例
http://blog.ch-wind.com/ue4-profiling-preview/ Profililng是成品制作过程中非常重要的一个步骤,通过Profiling才能提高运行效率使得作品达到用户能够运行从程度。 UE4本身有提供用于Profiling的工具,但是要正确的将其用于优化却需要经过一些学习。在掌…...