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

C++的第一道门坎:类与对象(一)

1.面向过程与面向对象

1.1面向过程

我们之前学习的C语言就是一种面向过程的语言,面向过程的语言强调的是具体实现的过程,一般用函数来具体实现。我们用面向过程的思想,就可以把炒菜分为以下几个步骤:

1.2面向对象

而对于面向对象的语言而言,它将问题分为了多个对象,问题的解决由对象之间的交互完成,而不再注重对象完成事情的具体过程,譬如上述炒菜的过程我们即可抽象为人、菜、锅的交互。

C++即是一门面向对象的语言,我们更强调对象之间的交互,而并不在意对象该如何解决问题。 

1.3对比

面向过程的语言和面向对象的语言各有其优缺点:

面向过程的语言流程化分工明确,效率高,但可维护性差,拓展能力差。

面向对象的语言结构化更清晰,易维护,但开销大,性能低。

2.类的引入

在C++中,我们在结构体的基础上引入了类(class)的概念,并对struct在CPP的基础上重新进行了解释。

由于我们的面向对象不注重过程的实现,但是对象本身还是需要实现过程的,因此我们要给对象加上一定的过程,比如我们的人锅交互可以炒菜,我们就要在类中声明一个作用是炒菜的函数。

也就是说,CPP的类和结构体中可以定义成员函数!

2.1类的声明方式

在C++中,有一个关键字为class,我们可以使用这个关键字来声明一个类,类内可以声明成员函数和成员变量,其语法结构为:

class 类名
{//类内的成员函数和成员变量
};

现在我们声明一个名为duanku的类:

class duanku
{int a;//成员变量int Add(int a, int b);//成员函数
};

2.2类的成员的两种定义方式

在定义类时,我们可以将类的定义与声明在同一文件书写,也可以在不同文件内书写。

2.2.1单文件定义

定义一个类,自然需要实现类体内的函数,我们可以将函数在类内定义,如下所示:

class duanku
{int a;//成员变量int Add(int a, int b)//成员函数{return a + b;}
};

这里需要大家注意的是:成员函数若在类内定义,则可能会被编译器当作内联函数处理。

2.2.2多文件定义

一个类也可以分为两个文件来实现,我们可以将成员函数的定义放在cpp文件内部。

但这儿需要大家注意的一点是:你定义的函数是谁的函数呢?是只在这个文件内部用的,还是实现了哪个地方的声明呢?因此,我们需要加域作用限定符,让编译器知道我们实现的是哪个函数。

//.h文件
class duanku
{int a;//成员变量int Add(int a, int b);//成员函数
};
//.cpp文件
int duanku::Add(int a, int b)
{return a + b;
}

 PS:在日常使用时,我们可以将定义和声明都放在类中。但是在实际的工程中,更倾向于将声明和定义分离。

3.类的访问限定符与封装

3.1访问限定符

在C++类中有三种访问限定符:public、private、protect

它们的作用如下

  • public修饰的成员可以在类外直接访问
  • private和protect修饰的成员在类外不可直接被访问(后续文章会详细解释private和protect)
  • 一个类中可以有多个访问限定符,一个限定访问符的作用域该限定访问符出现的位置到下一个限定访问符出现的位置,如果后面没有限定访问符,则到类结束的位置为止。
  • class的默认访问权限为private,struct的默认访问权限为public(下篇文章中会给出class和struct的详解)

3.2封装

封装:用类将对象的属性(数据)与操作数据的方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

通俗的说,封装其实是一种管理,是为了方便让用户更方便的使用类的一种方法。

比如说:对于一台电脑而言,我们提供给用户的是一系列的USB接口,我们可以通过它们和计算机进行一系列的交互,也可以自由更改每个USB接口的接什么,但是我们无法更改电脑的硬件元件。

这里,我们可以这样理解:

每个USB接口都是一个函数,我们可以自由更改它们,它们的访问限定为public。

而硬件元件则是类中的私有成员,不让外界访问,它们的访问限定为private。

4.类对象

4.1类对象的实例化

在类中定义的成员变量实际上是一种声明,而我们利用类名字定义的对象就是类对象的实例化

即,用类的类型创造对象的过程,称为类的实例化

1.类是对对象进行描述的,是一个模型一样的东西,限定了类中有哪些成员,定义出一个类并不会分配实际的内存空间来存储它。

2.一个类可以实例化出多个对象,实例化出的对象才占用实际的内存空间,存储的是类的成员变量。

我们不可以直接利用类来进行定义,如下图所示

 正确的定义方法如下:

	Date a;a._year = 3;

4.2类对象的存储

我们已经知道了类对象的创建方式,那么具体类中的成员变量与成员函数又是如何存储的呢?

4.2.1 存储方式1

每次创建对象时,都开辟一个空间存储类中的成员变量与成员函数。

但是这样存储就会出现一个问题,成员函数都是用的一个函数,我们每次都创建一个岂不是会有很大的开销吗?一个就能行的事儿为什么要用很多个呢?

于是,我们的计算机中,大多数都不是这么存储对象的。

4.2.2 存储方式2

 我们首先将成员函数放在外面,之后我们每次创建对象时,都开辟一个空间存储类成员变量与成员函数的地址,需要成员函数的时候直接按照地址去找。

4.2.3存储方式3

每次创建对象时,都开辟一个空间存储类成员变量。而成员函数提前单独存储在另外一个区域(公共代码段)。

之后我们没去用到成员函数时,都去那个区域里面拿出来用。

一般的编译器采用的都是存储模式2或存储模式3,具体使用的是哪种存储模式,我们可以通过计算类大小来进行判断。 

4.3类对象的大小

4.3.1普通类对象的大小

类型对象的大小也遵循结构体的内存对齐规则:

1.类的第一个成员对齐到结构体变量起始位置偏移量为0的地址处

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

   对齐数=编译器默认的一个对齐数与该成员变量大小的较小值

   --VS2022中的默认对齐数是8

   --Liunx中gcc没有默认对齐数,对齐数就是成员自身的大小

3.类总大小为所有成员对齐数中的最大对齐数的整数倍

4.如果嵌套了结构体,嵌套的结构体成员对齐到自己的成员的最大对齐数处,结构体的整体大小就是所有成员的最大对齐数(含嵌套结构体成员)的整数倍。

当然,类大小的计算我们可以也借助sizeof计算。

#include<iostream>
using namespace std;
class Date
{
//可以被直接访问
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}
//不能被直接访问
private:int _year;int _month;int _day;
};
int main()
{Date d;cout << sizeof(d) << endl;return 0;
}

 

由此可见,我们这里算出来的12是三个int类型的总和,而我们的成员函数则被放到了公共代码段中。 若是使用的存储模式2的话,则应该是12+成员函数地址的大小(32位系统是4,64位系统是8)。

 4.3.2空类的计算

当类中只有成员函数,或者什么都没有时,类的大小是多少呢?

class A
{
public:void func(){;}
};
class B
{
};
int main()
{A a;B b;cout << sizeof(a)<<endl << sizeof(b);return 0;
}

 

这里我们发现空类的大小为1,现在我们可以思考这么一个问题,为什么空类的大小是1而不是0呢? 这是因为我们在进行空类的实例化时必须要有空间表示我们在这儿存储了一个对象。这时编译器就会默认给一个字节大小来标记这个对象

5.this指针

5.1this指针的由来

#include<iostream>
using namespace std;
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;
}

在这里我先给大家抛出这么一个问题:为什么d1调用Init函数时,该函数知道是给d1对象调用Init,而不是给d2对象调用Init呢? 

在C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数。通过不同的对象地址来分辨不同的对象,只不过所有的操作对用户是透明的的,即用户不需要来传递,编译器自动完成。实际代码如下:

void Init(Date* this, int year, int month, int day)
{this->_year = year;this->_month = month;this->_day = day;
}
d1.Init(&d1,2022, 1, 11);//实际传参

5.2this指针的特点

  1. this指针额类型为const,即我们无法给this指针赋值
  2. this指针的本质是“成员函数”的形参,当对象调用成员函数时,会将对象的地址当作实参传递给形参。
  3. this指针只能在成员函数中使用
  4. this指针是“成员函数”第一个隐藏起来的指针形参,一般由编译器放在通过eax寄存器自动传递,不需要用户传递

5.3两个问题

5.3.1问题1

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class duanku
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{duanku* p = nullptr;p->Print();(*p).Print();return 0;
}

这段代码是可以正常运行的,虽然p是一个空指针,但是由于我们的成员函数放在公共代码段中,因此我们还是可以找到这个函数的,不会因为对空指针解引用而找不到它。

5.3.2问题2

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class duanku
{
public:void Print(){cout << _a << endl;}
private:int _a;
};
int main()
{duanku* p = nullptr;p->Print();(*p).Print();return 0;
}

这里就会让程序崩溃,因为函数中访问了_a ,nullptr->_a程序就崩溃了。

 6.成员变量的命名

大家在使用类时,可能会出现以下这么一个问题:

这时为了解决问题这类问题,我们在定义成员变量时会对其进行特定地修饰。比如说_变量名或者变量名_。不同公司,不同的程序员可能都有一套自己的命名规则,这里我们采用第一种。

由此我们可以将上述代码改写为这样:

class Date
{void Init(int year, int month, int day){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};

相关文章:

C++的第一道门坎:类与对象(一)

1.面向过程与面向对象 1.1面向过程 我们之前学习的C语言就是一种面向过程的语言&#xff0c;面向过程的语言强调的是具体实现的过程&#xff0c;一般用函数来具体实现。我们用面向过程的思想&#xff0c;就可以把炒菜分为以下几个步骤: 1.2面向对象 而对于面向对象的语言而言…...

经典面试题:MySQL如何调优?

目录 前言1. SQL查询优化2. 索引优化3. 表结构设计4. 硬件与配置优化5. 日常维护6. 性能测试与基准测试 前言 MySQL如何进行调优&#xff1f;这是面试中容易被问到的高频问题。 1. SQL查询优化 避免使用select* &#xff1a;只选取需要的列&#xff0c;减少数据传输量。使用…...

【程序员如何送外卖】

嘿&#xff0c;咱程序员要在美团送外卖&#xff0c;那还真有一番说道呢。 先说说优势哈&#xff0c;咱程序员那逻辑思维可不是盖的&#xff0c;规划送餐路线什么的&#xff0c;简直小菜一碟。就像敲代码找最优解一样&#xff0c;能迅速算出怎么送最省时间最有效率。而且咱平时…...

【git pull 和 push详解】

git pull 和 push详解 1.背景2.命令和解释2.1 git pull简介详情 2.2 git push简介Git Push 参数及详细解释 1.背景 在分布式开发环境中&#xff0c;git pull和git push的使用确保了团队成员之间的代码一致性&#xff0c;减少了不同步导致的问题。它们简化了版本管理&#xff0c…...

数据挖掘导致直接路径读(direct path read)耗尽了IO

一大早就有喊业务卡的&#xff0c;检查等待事件源头&#xff0c;均为oracle写等待 查看IO负载持续维持在100%繁忙 后台有两个并行rman备份在&#xff0c;停止备份io繁忙没有好转&#xff0c;检查最近ash报告&#xff0c;发现DDTEK ODBC Oracle程序模块占用最高 检查该模块&…...

用队列实现栈 用栈实现队列 设计循环队列

用队列实现栈 思路 栈的特点&#xff1a;后进先出 队列的特点&#xff1a;先进先出 使用两个队列实现栈&#xff1a; 我们可以使用两个队列&#xff0c;一个队列为&#xff1a;空队列&#xff0c;一个队列为&#xff1a;非空队列 当我们要出队列时&#xff1a; 将 size - …...

BFS解决最短路问题(详解)

目录 BFS简介 && 框架&#xff1a; 一.二叉树的最小深度 二&#xff1a;迷宫中里入口最近的出口&#xff1a; 三.最小基因变化: 四&#xff1a;单词接龙&#xff1a; ​五&#xff1a;为高尔夫比赛砍树&#xff1a; BFS简介 && 框架&#xff1a; 说到BFS…...

按尺寸筛选轮廓图中的轮廓

1.按短边筛选 原始轮廓图&#xff1a; import cv2 import numpy as np# 读取轮廓图 contour_image cv2.imread(..\\IMGS\\pp_edge.png, cv2.IMREAD_GRAYSCALE)# 使用cv2.findContours()函数获取所有轮廓 contours, _ cv2.findContours(contour_image, cv2.RETR_EXTERNAL, cv2…...

VBA高级应用30例:实现在列表框内及列表框间实现数据拖动

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…...

「AIGC算法」R-tree算法

R-tree算法是一种非常实用的空间数据索引技术,它可以帮助我们在复杂的空间数据中快速找到我们想要的信息。下面我将用一些生活中的例子来帮助大家更好地理解R-tree算法。 1. 定义与原理 想象一下,你有一个巨大的图书馆,里面有成千上万本书,每本书都有它在书架上的特定位置…...

2024软考上半年嵌入式系统设计师考试回顾

一&#xff1a;考试准备工作 1&#xff1a;基本上都是提前30分钟进考场&#xff0c;进入考试教室的时候&#xff0c;会有监考老师核对身份证和准考证&#xff1b; 2&#xff1a;进入考试教室之后&#xff0c;会再一次核对身份信息&#xff0c;并且有监考老师手持扫描仪&#x…...

MIT6.828 Lab2-1 Using gdb

Using gdb gdb使用&#xff1a; xv6 gdb调试方法 问题1&#xff1a; Looking at the backtrace output, which function called syscall? 按照提示开启gdb后键入&#xff1a; b syscall c layout src backtrace输出结果&#xff1a; (gdb) backtrace #0 syscall () at k…...

mysqldump提示Using a password on the command line interface can be insecured的解决办法

mysql数据库备份一句话执行命令 mysqldump --all-databases -h127.0.0.1 -uroot -p123456 > allbackupfile.sql 提示如下提示 [rootyfvyy5b2on3knb8q opt]# mysqldump --all-databases -h127.0.0.1 > allbackupfile.sql mysqldump: Couldnt execute SELECT COLUMN_NA…...

Java毕业设计 基于springboot vue考勤管理系统

Java毕业设计 基于springboot vue考勤管理系统 SpringBoot 考勤管理系统 功能介绍 员工 登录 个人中心 修改密码 个人信息 员工请假管理 员工出差管理 薪资管理 员工签到管理 公告管理 管理员 登录 个人中心 修改密码 个人信息 员工管理 员工请假管理 员工出差管理 薪资管理…...

C数据结构:二叉树

目录 二叉树的数据结构 前序遍历 中序遍历 后序遍历 二叉树的创建 二叉树的销毁 二叉树的节点个数 二叉树叶子节点个数 二叉树第K层节点个数 二叉树的查找 层序遍历 判断二叉树是否为完全二叉树 完整代码 二叉树的数据结构 typedef char BTDataType; typedef str…...

使用Nginx作为反向代理实现MQTT内外网通信

使用Nginx作为反向代理实现MQTT内外网通信 步骤1: 安装Nginx 确保你的服务器上已安装Nginx。如果未安装&#xff0c;可以通过以下命令在Ubuntu上安装Nginx&#xff1a; sudo apt update sudo apt install nginx步骤2: 配置Nginx 编辑Nginx的配置文件&#xff0c;通常是/etc…...

SpringBoot 上传文件示例

示例效果&#xff1a; 前端代码&#xff1a; <html> <head><title>上传文件示例</title></head> <body> <h2>方式一&#xff1a;普通表单上传</h2> <form action"/admin/upload" method"post" enctyp…...

9.js函数

函数是js复杂数据类型的一种---可以理解为存放代码的盒子 用来帮助我们封装、复用、扩展以及调用代码的工具 函数的两个阶段 &#xff08;1&#xff09;声明函数&#xff08;理解为创造&#xff09; ——声明式声明 语法&#xff1a;function 函数名(参数){...代码} ——赋值时…...

关于数据库和数据表的基础SQL

目录 一. 数据库的基础SQL 1. 创建数据库 2. 查看当前有哪些数据库 3. 选中数据库 4. 删除数据库 5. 小结 二. 数据表的基础SQL 1. 创建数据表 2. 查看当前数据库中有哪些表 3. 查看指定表的详细情况(查看表的结构) 4. 删除表 5. 小结 一. 数据库的基础SQL 1. 创建…...

【C语言深度解剖】(14):结构体内存对齐(详细配图讲解)

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《C语言深度解剖》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多C语言深度解剖点击专栏链接查看&…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...