Cpp类和对象(上)(3)
文章目录
- 前言
- 一、面向过程与面向对象初步认识
- 二、类的引入
- 三、类的定义
- 四、类的访问限定符及类的封装
- 类的访问限定符
- 类的封装
- 五、类的作用域(类域)
- 六、类的实例化
- 七、类对象模型
- 如何计算类对象的大小
- 类对象的存储方式猜测
- 八、this指针
- this指针的引出
- this指针的特性
- 九、C语言和C++实现Stack的对比
- 总结
前言
哈哈,类和对象可以说是我们正式学习Cpp的第一节课
上篇还不算很难,甚至可以说还是蛮有意思的
正文开始!
一、面向过程与面向对象初步认识
你需要很早地有个认识:
- C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
- C++是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间的交互完成。
举个例子,假设你点了一份外卖:
面向过程: 你下单——商家做饭——骑手取餐——商家骑手交接——骑手送餐——你拿到饭菜
面向对象: 骑手、商家、顾客这三个 类 实例化产生的对象之间的交互
二、类的引入
在C语言中,结构体中只能定义变量,但在C++中,结构体内不仅可以定义变量,还可以定义函数
struct Test
{//成员变量int a;double b;//成员函数int Add(int x, int y){return x + y;}
};
可是,我们在C++中更喜欢用 class 来代替,下面来看类的定义:
class className
{// 类体:由成员函数和成员变量组成}; // 一定要注意后面的分号
类体中内容称为类的成员,其中类的成员:
- 类中的变量称为类的属性或成员变量
- 类中的函数称为类的方法或成员函数
三、类的定义
声明和定义全部放在类体中
请注意,成员函数如果在类中定义,编译器可能会将其当成内联函数处理
声明放在头文件(.h)中,定义放在源文件(.cpp)中
请注意,成员函数名前需要加 “类名::”
一般情况下,更期望采用第二种方式,因为这样体现了面对对象编程的封装特性,提高代码的可维护性
你再看上面这两段代码的成员变量,你可能奇怪为什么每个变量前都有个下划线_,这是为了与成员函数的形参区分开:
class Date
{
// 你可能奇怪这个 public 和 private,先不急哈
public:void Init(int year){// 区分一个类的成员变量和成员函数的形参,通常将成员变量前或者后加一个“_”_year = year;// 如若成员变量不加“_”,就变成了year = year; 局部变量优先,导致错误}
private:int _year;
};
四、类的访问限定符及类的封装
类的访问限定符
C++实现封装的方式:用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限,选择性的将其接口提供给外部的用户使用
在我们还没学到继承之前,你暂时先把ptotected 和 private 等同吧
- public修饰的成员(成员函数或者成员变量)在类外可以直接被访问;
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的);
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止;
- 如果后面没有访问限定符,作用域就到 }, 即类结束;
- class的默认访问权限为private,struct为public(因为struct要兼容C);
请注意,访问限定符只在编译时期有效,当数据映射到内存后,没有任何访问限定符的区别
类的封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
绝对的自由不是自由,印度火车不加以管制,导致一辆车除了座位,旁侧扶手甚至车顶都可以载人,危险程度无可置疑地增大,而封装本质上是一种高效的管理,对访问权限的限制有时候是为了我们更好的使用,这点大家可以有个意识,慢慢再来体会
再比如计算机,用户无需关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可
因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可
五、类的作用域(类域)
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用“::”作用域解析符指明成员属于哪个类域
class Person
{
public:// 显示基本信息void ShowInfo();
private:char* _name; //姓名char* _sex; //性别int _age; //年龄
};//这里需要指定 ShowInfo 是属于 Person 这个类域
void Person::ShowInfo()
{cout << _name << "-" << _sex << "-" << _age << endl;
}
六、类的实例化
用类创建对象的过程称为类的实例化
类本质上也是一种数据类型(如int,float,double等)只不过类是一种比较复杂的数据类型,它包含多种可自助实现的功能(类的成员函数),既然如此,那类其实并没有实际分配空间,如果出现没有对类进行实例化操作,而私自调用类中成员变量会报错,而通过类实例化出来的对象是占用内存空间的
简单来说,类就像图纸,你得用它来建设房子
七、类对象模型
如何计算类对象的大小
我们先来看以下代码:
#include<iostream>
using namespace std;class A1 {
public:void f1(){}
private:int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};int main()
{// 4 1 1cout<<sizeof(A1)<<" "<<sizeof(A2)<<" "<<sizeof(A3);return 0;
}
注意结构体内存对齐
可以看出来输出结果为 4、1、1,这可以引发我们的一些猜测:
类对象的存储方式猜测
猜测一:对象中包含类的各个成员
观察到A1的输出结果为4,否决,其实我们分析以下,道理也很显然,假如每个实例化的对象的成员函数都开空间,那有一百个实例化对象就开一百份空间,而这些实例化的对象的属性固然不一样,但函数却是一样的,这造成了浪费
猜测二:只保存成员变量,成员函数存放在公共的代码段
这就解释了为什么A1的大小为4,但是为什么A2和A3的大小不是0而是1呢?
你分析一下,什么是定义,什么是声明,定义是确确实实要开空间的,尽管没有属性,但我们仍要标记一下,所以空类比较特殊,编译器给空类一个字节来唯一标识这个类的对象,表示这个对象存在过,可能有成员函数
八、this指针
this指针的引出
#include <iostream>
using namespace std;class Date
{
public:void Display(){cout << _year << "-" << _month << "-" << _day << endl;}void SetDate(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year; // 年int _month; // 月int _day; // 日
};int main()
{Date d1, d2;//实例化两个日期类d1.SetDate(2021, 5, 25);//设置d1的日期d2.SetDate(2021, 5, 26);//设置d2的日期d1.Display();//打印d1的日期d2.Display();//打印d2的日期return 0;
}
我们观察,Date 类中有 Init 与 Print 两个成员函数,对于函数体没有关于不同对象的区分,当不同对象调用函数时,该函数如何知道应该设置或打印 d1对象 ,而不是 d2对象 呢
C++中通过引入 this 指针解决该问题,即:C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
编译器进行编译时,看到的成员函数实际上也和我们所看到的不一样,每个成员函数的第一个形参实际上是一个隐含的this指针,该指针用于接收调用函数的对象的地址,用this指针就可以很好地访问到该对象中的成员
this指针的特性
- this指针的类型:类类型* const,即成员函数中,不能给this赋值
- this指针只能在“成员函数”的内部使用。
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况this指针存在栈里面,因为是形参。或者由编译器通过ecx寄存器自动传递,不需要用户传递。
不妨我们再通过以下代码来深入了解this指针:
#include <iostream>
using namespace std;class A
{
public:void PrintA(){cout << _a << endl;}void Show(){cout << "Show()" << endl;}
private:int _a;
};int main()
{A* p = nullptr; //p->Show(); // 第一句代码//p->PrintA(); // 第二句代码
}
你可能看到指针p是一个空指针,而第二句代码和第三句代码都通过操作符“->”,间接性的执行了对p的解引用操作,所以你认为程序会崩溃
其实不然,当程序执行第一句代码时,程序不会崩溃,会正常打印出字符串"Show()",而当程序执行第二句代码时,程序才会因为内存的非法访问而崩溃
不要陷入思维固化,指针p确实是一个类的空指针,但当执行第一句代码时,程序并不会崩溃。第一句代码并没有对空指针p进行解引用,因为Show等成员函数地址并没有存到对象里面,成员函数的地址是存在公共代码段的。
当程序执行第二句代码时,会因为内存的非法访问而崩溃。执行第二句代码时,调用了成员函数PrintA,这里并不会产生什么错误(理由同上),但是PrintA函数中打印了成员变量_a,成员变量_a只有通过对this指针进行解引用才能访问到,而this指针此时接收的是nullptr,对空指针进行解引用必然会导致程序的崩溃
九、C语言和C++实现Stack的对比
C语言实现栈
观察C语言实现,我们会发现:
- 每个函数的第一个参数都是Stack*
- 函数中必须要对第一个参数检测,因为该参数可能会为NULL
- 函数中都是通过Stack*参数操作栈的
- 调用时必须传递Stack结构体变量的地址
结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。
Cpp实现栈
观察C++实现,我们会发现:
C++中通过类可以将** 数据 以及 操作数据的方法进行完美结合**,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要传递Stack的参数了,编译器编译之后该参数会自动还原,即C++中 Stack 参数是编译器维护的,C语言中需用用户自己维护
总结
怎么样,本节内容开始有意思了起来,接下来的中篇会更有意思!
相关文章:

Cpp类和对象(上)(3)
文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言…...
【微信小程序】连续拍照功能实现
前言: 最近在使用uniapp开发微信小程序,遇到这样一个需求,用户想要连续拍照,拍完之后可以删除照片,保留自己想要的照片,然后上传到服务器上。由于原生的方法只能一个个拍照上传,所以只能自己通过…...
JavaSE:11、内部类
学习 资源1 学习资源 2 1、成员内部类 import com.test.*;public class Main {public static void main(String [] argv){Person personnew Person();//Person构造函数Person.Woman womanperson.new Woman();//woman构造函数} }package com.test;public class Person {publ…...

VTD激光雷达(7)——07_OptiX_Variables_Advanced
文章目录 前言一、总结 前言 一、 1 和上图蓝绿的区别在于 总结...
运维工程师面试整理-自动化运维
自动化运维是现代运维工作中不可或缺的一部分,它可以大幅提升效率,减少人为错误,并使得大规模环境管理变得可行。在面试中,面试官通常会通过自动化运维相关的问题来评估你在自动化工具使用、脚本编写、CI/CD 实践以及系统监控等方面的能力。以下是关于自动化运维的详细内容…...

【JAVA基础】实现Tomcat基本功能
文章目录 TCP/IP协议Socket编程ServletTomcat 在搜索了两三天之后,也是大概弄懂了Tomcat是个什么东西,我们在说Tomcat之前,先来了解一下下面这三个东西: TCP/IP协议 TCP/IP 是互联网通信的基础协议。TCP(传输控制协议…...

风力发电叶片缺陷检测数据集
风力发电叶片缺陷检测数据集】nc: 4 names: [Burn Mark, Coating_defects, Crack, EROSION ] 名称:【烧伤痕迹, 涂层缺陷, 裂缝,侵蚀】共1095张,8:1:1比例划分,(train;876张,val:109张ÿ…...
数据类型自动转换的解决方案
数据类型自动转换的解决方案 java8、jdk8背景 为方便测试框架数据处理以及方便查看一些数据,弄了一个工具类,部分要点简要说明。 主要涉及到字符串与其他类型的相互转换,无其他类型之间的相互转换。 轻量测试框架实现与使用的总篇可见此文…...
大厂校招:唯品会Java面试题及参考答案
SortedSet 的原理 SortedSet 是一个有序的集合接口,它继承自 Set 接口。在 Java 中,常见的实现类有 TreeSet。 TreeSet 实现了 SortedSet 接口,它使用红黑树来维护集合中元素的有序性。红黑树是一种自平衡的二叉搜索树,具有以下特点: 每个节点要么是红色,要么是黑色。根节…...

Qt常用控件——QLCDNumber
文章目录 QLCDNumber核心属性倒计时小程序倒计时小程序相关问题 QLCDNumber核心属性 QLCDNumber是专门用来显示数字的控件,类似于这样: 属性说明intValue获取的数字值(int).value获取的数字值(double)和intValue是联动的例如value设为1.5,in…...

专业学习|GERT网络概览(学习资源、原理介绍、变体介绍)
一、GERT 网络概览 GERT(Graphical Evaluation Review Technique,图示评审技术)是一种结合流线图理论(Flow Graphical Theory)、矩母函数(Moment Generating Function)、计划评审技术(Program Evaluation Review Technique)解决随机网络问题的方法,描述各…...

搭建一个基于角色的权限验证框架
说明:基于角色的权限验证(Role-Based Access Control,RBAC)框架,是目前大多数服务端的登录校验框架。本文介绍如何快速搭建一个这样的框架,不用Shiro、Spring Security、Sa-Token这样的“大框架”实现。 R…...

下载chromedriver驱动
首先进入关于ChromeDriver最新下载地址:Chrome for Testing availability 进入之后找到与自己所匹配的,在浏览器中查看版本号,下载版本号需要一致。 下载即可,解压,找到 直接放在pycharm下即可 因为在环境变量中早已配…...

在STM32工程中使用Mavlink与飞控通信
本文讲述如何在STM32工程中使用Mavlink协议与飞控通信,特别适合自制飞控外设模块的项目。 需求来源: 1、增稳云台里的STM32单片机需要通过串口接收飞控传来的云台俯仰、横滚控制指令和相机拍照控制指令; 2、自制的有害气体采集器需要接收飞…...

【Elasticsearch】-7.17.24版本接入
官网 https://www.elastic.co/cn/downloads/elasticsearch 本项目基于windows环境下,其他环境操作类似 1、初始化配置 打开config/elasticsearch.yaml 添加如下配置 cluster.name: dams_clusternetwork.host: 127.0.0.1 http.port: 9200# 不开启geo数据库 inge…...

ShouldSniffAttr在自动化测试中具体是如何应用?
在自动化测试中,ShouldSniffAttr 这样的函数名通常暗示它是一个用于断言(assertions)的工具,用于检查某个元素或属性是否符合预期的条件。 虽然这不是一个标准的函数名,但我们可以根据命名推测其用途。 例如…...

前端vue3打印,多页打印,不使用插件(工作中让我写一个打印功能)
说下总体思路,创建一个组件,里面放多个span字段,然后根据父组件传入的参数,生成子组件,最好我们打印子组件的信息即可。通过我多次ai,探索最后成功了。 子组件代码 media print 这个我要讲一下ÿ…...
传感技术是如何实现实时监测和控制的呢
传感技术在力士乐拧紧系统中实现实时监测和控制的方式主要通过以下几个步骤进行: 一、传感器数据采集 1. 传感器种类: 力士乐拧紧系统中可能包含多种传感器,如力矩传感器、角度传感器和转速传感器等。这些传感器各自负责检测拧紧过程中的不…...

为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办
你是否遇到过这样的情况,下载了一个rar文件,想要查看里面的内容,却发现Mac电脑无法打开。rar文件是一种常见的压缩文件格式,它可以将多个文件或文件夹压缩成一个文件,节省空间和传输时间。如此高效实用的压缩文档&…...
linux下日志系统setvbuf接口及结构体 handle_file_t成员介绍
typedef struct handle_file_t {uint8_t *wkey;//用于存储写入文件时可能需要的加密密钥int cflag;//用于表示日志文件的某些配置标志,例如是否启用压缩、是否启用加密等char *file_path;//用于存储日志文件的路径FILE *…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...