当前位置: 首页 > news >正文

【C++杂货店】类和对象(上)

【C++杂货店】类和对象(上)

  • 一、面向过程和面向对象初步认识
  • 二、类的引入
  • 三、类的定义
  • 四、类的访问限定符及封装
    • 4.1 访问限定符
    • 4.2 封装
  • 五、类的作用域
  • 六、类的实例化
  • 七、类对象模型
    • 7.1 类对象的存储规则
    • 7.2 例题
    • 7.3结构体内存对齐规则
  • 八、this指针
    • 8.2 this指针的特性
    • 8.3 经典面试题
      • 面试题(一)
      • 面试题(二)


在这里插入图片描述


一、面向过程和面向对象初步认识

 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
在这里插入图片描述


 C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
在这里插入图片描述


二、类的引入

C语言结构体中只能定义变量,在C++中,结构体升级成类内不仅可以定义变量,也可以定义函数。比如:之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现struct中也可以定义函数。

Cpp代码演示

struct Stack
{//函数void Init(){a = nullptr;capacity = top = 0;}void Push(int x){a[top] = x;top++;}// ....其他函数//变量int* a;int top;int capacity;
};

但在CPP中更喜欢用class来代替struct,接下面我们来看看class用法(后面会介绍两者区别)。


三、类的定义

class ClassName
{
// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号

class为定义类的关键字ClassName为类的名字,{ }中为类的主体,注意类定义结束时后面分号不能省略
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数

类的两种定义方式

  1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
    在这里插入图片描述
  2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
    在这里插入图片描述

四、类的访问限定符及封装

4.1 访问限定符

C++通常是将对象和方法封装到一起,通过访问权限的选择性将接口提供给外部用户。 而访问权限分为以下3种:在这里插入图片描述
【访问限定符说明】

  1. public修饰的成员在类外可以直接被访问, protected和private修饰的成员则相反。(此处protected和private是类似的)
  2. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。 如果后面没有访问限定符,作用域就到 } 即类结束。
  3. class的默认访问权限为private,struct为public。(因为struct要兼容C)

Tips:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

经典面试题】:C++中struct和class的区别是什么?
答案:C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。


4.2 封装

封装将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
在这里插入图片描述
但对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可


五、类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。(类和其他作用域不同,编译时它是一个整体,定义变量时可以在任何地方,编译器会在类的作用域种全局查找)

【代码演示】

class Date
{
public:void Print();private:int _year;int _month;int _day;
};//类体外定义成员函数
void Date::Print()
{cout << "_year" << "_month" << "_day" << endl;
}

六、类的实例化

用类的类型创建对象的过程,称为类的实例化。

类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。但一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量

做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
在这里插入图片描述


七、类对象模型

7.1 类对象的存储规则

我们先来看看这段代码,求类和对象的大小。

class A
{
public:
void PrintA()
{cout<<_a<<_i<<_d<<endl;
}private:
char _a;
int _i;
double _d;
};

类中既可以有成员变量,又可以有成员函数。这里先说下成员变量和结构体的计算规则是一样的,但成员函数呢?

由于每个对象中成员变量是不同的,但是调用同一份函数,如果按照普通函数方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,造成空间浪费。因此,在C++中,对于类我们只保存成员变量,而成员函数存放在公共的代码段
在这里插入图片描述

7.2 例题

// 类中既有成员变量,又有成员函数
class A1 {
public:void f1(){}
private:int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};

求:sizeof(A1) : ______ sizeof(A2) : ______ sizeof(A3) : ______(结果:4、1、1)

解析: A1的大小为4byte毫无疑问。但A2中仅有一个函数位于公共代码区不算大小,A3更绝空类。对于这种特殊情况,C++定义其大小为1byte(占位,不存储数据,仅仅表示对象存在过

总结: 一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐。注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。(表示占位,不存储数据,仅仅表示对象存在过

7.3结构体内存对齐规则

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

【经典面试题】

  1. 结构体怎么对齐? 为什么要进行内存对齐?
  2. 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?
  3. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景?

八、this指针

我们先来定义一个日期类 Date

class Date
{
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()
{Date d1, d2;d1.Init(2022, 1, 11);d2.Init(2022, 1, 12);d1.Print();d2.Print();return 0;
}

对于上述类,有这样的一个问题:
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

8.2 this指针的特性

  1. this指针的类型:类的类型const*,即成员函数中,不能给this指针赋值。
    2.this指针只能在“成员函数”的内部使用。( this在实参和形参位置不能显示写, 但是在类里面可以显示的用)
  2. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
  3. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

在这里插入图片描述

8.3 经典面试题

面试题(一)

【面试题】:

  1. this指针存在哪里?
  2. this指针可以为空吗?

答案: this指针存在栈区。this指针不可以为空。因为this指针是一个隐含的参数,它指向当前对象的地址。当我们在类的成员函数内部使用this指针时,它指向调用该函数的对象。由于每个对象都有自己的地址,因此this指针始终指向一个有效的对象。

面试题(二)

我们在来看看腾讯的这道面试题:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
//解析:本题主要在于P是否真的进行了空指针的解引用。
//     由于p指向的成员变量,但Print函数实际存在公共代码区(和全局变量类似)
//      所以实际上编译器是不会对p进行解引用。而是直接去符号表中查找Print函数地址。所以答案为C// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:void PrintA() {cout<<_a<<endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}
//解析:这上面一样,编译器不会对p进行空指针的解引用,而是将p作为this指针传给PrintA函数。
//      而PrintA函数中,需要通过this(即p的形参)解引用指向_a,对空指针进行非法行为,运行崩溃

好了,本篇博客到此就结束了,希望能帮助到你。
在这里插入图片描述
在这里插入图片描述

相关文章:

【C++杂货店】类和对象(上)

【C杂货店】类和对象&#xff08;上&#xff09; 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类对象模型7.1 类对象的存储规则7.2 例题7.3结构体内存对齐规则 八、this指针8.2 t…...

K8S笔记

...

MySQL关于日期函数的使用-笔记

韩老师笔记 select current_time select CURRENT_DATE create table mes ( id int, content VARCHAR(255), send_time DATETIME ) select * from mes; insert into mes values(1,北京,CURRENT_DATE) insert into mes (id,send_time) values(2,CURRENT_TIME) insert into mes v…...

【postgresql 】 ERROR: “name“ is not supported as an alias

org.postgresql.util.PSQLException: ERROR: "name" is not supported as an alias 错误&#xff1a;不支持将“name”作为别名 SELECT real_name name FROM doc_user 加上 在关键词上加上 “” 示例&#xff1a; SELECT real_name "name" FROM do…...

都用HTTPS了,还能被查出浏览记录?

最近&#xff0c;群里一个刚入职的小伙因为用公司电脑访问奇怪的网站&#xff0c;被约谈了。他很困惑 —— 访问的都是HTTPS的网站&#xff0c;公司咋知道他访问了啥&#xff1f; 实际上&#xff0c;由于网络通信有很多层&#xff0c;即使加密通信&#xff0c;仍有很多途径暴露…...

vi配置文件.vimrc内容示例

1、.vimrc配置文件介绍 &#xff08;1&#xff09;.vimrc是vi编辑器的配置文件&#xff0c;里面可以对vi编译器做个性化配置&#xff1b; &#xff08;2&#xff09;.vimrc在用户目录下&#xff0c;每个用户有一个&#xff0c;类似于.bashrc文件&#xff0c;将下面的配置文件内…...

MacOS上的Pip和Python升级指南

在MacOS系统上&#xff0c;保持Pip和Python版本的最新状态对于顺利进行Python开发至关重要。通过升级Pip和Python&#xff0c;你可以享受到最新的功能、修复的bug以及提升的开发效率。本文将为你提供在MacOS上升级Pip和Python的详细指南&#xff0c;助你打造更强大的开发环境。…...

VB6.0实现修改EXE程序的图标

当你给一家公司做技术支持的时候&#xff0c;需求各种各样的&#xff0c;其中今天遇到就是要修改某个程序的图标&#xff0c;代码实现如下。 // q1016058890 群 214016721 //注 意&#xff1a;这个方法貌似只对有些EXE文件有效&#xff0c;这不是万能的方法&#xff0c;此…...

Python 编程基础 | 第二章-基础语法 | 2.3、for 语句

一、for 语句 1、循环语句 for循环的语法格式如下&#xff1a; for iterating_var in sequence:statements(s)例如&#xff1a; for ch in "hello world":print(ch)fruits ["banana", "apple", "mango"] for fruit in fruits:print(…...

linux下解决tomcat错误问题

错误一&#xff1a; Linux下Tomcat启动报错&#xff1a;Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 原因&#xff1a;可能是Linux环境变了&#xff0c;需要在catalina.sh文件里指定JDK路径 解决方式&#xff1a; 在/bin/catalina.sh配置文件中加…...

PMP证书的价值如何?

2022年开始&#xff0c;PMP考试启用了新考纲&#xff0c;不光考试内容进行了大刀阔斧的改革&#xff0c;出题方式也进行了更新。除原有的PMBOK6和PMBOK7主考教材外&#xff0c;还增加了一本《敏捷实践指南》。 别小看新加的这本书&#xff0c;它虽然与PMBOK代表的预测法属于完…...

linux上mysql数据备份(全量备份策略+增量备份策略)

执行备份策略前&#xff0c;先做好scp命令的准备 解决思路&#xff1a; 生成SSH公钥/私钥后&#xff0c;您需要将公钥添加到服务器上&#xff0c;从而使服务器可以使用该公钥来验证您的身份。 生成SSH公钥/私钥的命令为 ssh-keygen -t rsa -b 4096什么都不用输入&#xff0c…...

PHP实现DFA算法,查找关键词

# 添加关键词 到全局字典dict里面 protected function addWord($strWord) {$len mb_strlen($strWord,UTF-8);$curNode &$this->dict;for ($index 0; $index < $len; $index) {$word mb_substr($strWord, $index, 1, UTF-8);if (!isset($curNode[$word])) {$curNo…...

JTS:08 JTS图形相交

这里写目录标题 版本JTS disjoint intersects俩个图形不相交俩个图形 边相交俩个图形 内部相交俩个图形 点相交 版本 org.locationtech.jts:jts-core:1.19.0 链接: github JTS disjoint intersects 不相交的 九交模型FF*FF**** 相交的 九交模型 [T********] [*T*******] [**…...

深挖 ThreadLocal 底层原理?它有什么用?学会之后手撕面试官

目录 1. ThreadLocal 的主要功能&#xff1f; 2. ThreadLocal 代码举例 3. ThreadLocal 源码分析 3.1 ThreadLocal 的 get 方法源码解析 3.2 ThreadLocal 的 set 方法源码解析 3.3 ThreadLocal 的 createMap 方法源码解析 3.4 ThreadLocal 的 set 方法总结 4. 为什么En…...

sort()排序函数(c++)

文章目录 sort()排序函数&#xff08;c&#xff09;一、原理二、使用方法&#xff08;一&#xff09;头文件&#xff08;二&#xff09;使用语法1.方式一&#xff08;默认&#xff09;2.方式二&#xff1a;定义升序或降序3.方式三&#xff1a;自定义 sort()排序函数&#xff08…...

如何评估测试用例的优先级?

评估测试用例的优先级&#xff0c;有助于我们及早发现和解决可能对系统稳定性和功能完整性产生重大影响的问题&#xff0c;助于提高测试质量&#xff0c;提高用户满意度。 如果没有做好测试用例的优先级评估&#xff0c;往往容易造成对系统关键功能和高风险场景测试的忽略&…...

510758-28-8,用于标记蛋白质和酶的配体TBTA

产品简介&#xff1a;Tris(benzyltriazolylmethyl)amine (TBTA)是一种配体&#xff0c;能作为生化工具用于标记蛋白质和酶。 CAS号&#xff1a;510758-28-8 中文名&#xff1a;三[(1-苄基-1H-1,2,3-三唑-4-基)甲基]胺 英文名&#xff1a;TBTA 化学式&#xff1a;C30H30N10…...

Jtti:云服务器ftp不能访问端口如何解决

如果您的云服务器上的FTP服务无法访问端口&#xff0c;可能有多种原因导致这种情况。以下是一些可能的解决方法&#xff1a; 检查FTP服务状态&#xff1a; 首先&#xff0c;请确保您的FTP服务器正在运行。您可以使用以下命令来检查FTP服务器的状态&#xff0c;具体命令可能因FT…...

云服务器租用价格表概览_阿里云腾讯云华为云

云服务器租用价格多少钱一年&#xff1f;阿腾云分享阿里云、腾讯云和华为云的云服务器租用价格表&#xff1a;阿里云2核2G服务器108元一年起、腾讯云2核2G3M带宽轻量服务器95元一年、华为云2核2G3M云耀L实例89元一年起&#xff0c;阿腾云分享更多关于云服务器租用价格明细&…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...