Cpp类和对象(上)(3)

news2024/11/15 23:52:01

文章目录

  • 前言
  • 一、面向过程与面向对象初步认识
  • 二、类的引入
  • 三、类的定义
  • 四、类的访问限定符及类的封装
    • 类的访问限定符
    • 类的封装
  • 五、类的作用域(类域)
  • 六、类的实例化
  • 七、类对象模型
    • 如何计算类对象的大小
    • 类对象的存储方式猜测
  • 八、this指针
    • this指针的引出
    • this指针的特性
  • 九、C语言和C++实现Stack的对比
  • 总结


前言

  哈哈,类和对象可以说是我们正式学习Cpp的第一节课
  上篇还不算很难,甚至可以说还是蛮有意思的

正文开始!


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

你需要很早地有个认识:

  1. C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
  2. C++是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间的交互完成。

举个例子,假设你点了一份外卖:
  面向过程: 你下单——商家做饭——骑手取餐——商家骑手交接——骑手送餐——你拿到饭菜
  面向对象: 骑手、商家、顾客这三个 类 实例化产生的对象之间的交互

二、类的引入

在C语言中,结构体中只能定义变量,但在C++中,结构体内不仅可以定义变量,还可以定义函数

struct Test
{
	//成员变量
	int a;
	double b;
	
	//成员函数
	int Add(int x, int y)
	{
		return x + y;
	}
};

可是,我们在C++中更喜欢用 class 来代替,下面来看类的定义:

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

类体中内容称为类的成员,其中类的成员:

  1. 类中的变量称为类的属性成员变量
  2. 类中的函数称为类的方法成员函数

三、类的定义

声明和定义全部放在类体中

请注意,成员函数如果在类中定义,编译器可能会将其当成内联函数处理

在这里插入图片描述
声明放在头文件(.h)中,定义放在源文件(.cpp)中

请注意,成员函数名前需要加 “类名::”

在这里插入图片描述

  一般情况下,更期望采用第二种方式,因为这样体现了面对对象编程的封装特性提高代码的可维护性

  你再看上面这两段代码的成员变量,你可能奇怪为什么每个变量前都有个下划线_,这是为了与成员函数的形参区分开

class Date
{
// 你可能奇怪这个 public 和 private,先不急哈
public:
    void Init(int year)
    {
		// 区分一个类的成员变量和成员函数的形参,通常将成员变量前或者后加一个“_”
        _year = year;
        // 如若成员变量不加“_”,就变成了year = year; 局部变量优先,导致错误
    }
private:
    int _year;
};

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

类的访问限定符

  C++实现封装的方式:用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限,选择性的将其接口提供给外部的用户使用
在这里插入图片描述

在我们还没学到继承之前,你暂时先把ptotected 和 private 等同吧

  1. public修饰的成员(成员函数或者成员变量)在类外可以直接被访问;
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的);
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止;
  4. 如果后面没有访问限定符,作用域就到 }, 即类结束;
  5. 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 1
	cout<<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指针的特性

  1. this指针的类型:类类型* const,即成员函数中,不能给this赋值
  2. this指针只能在“成员函数”的内部使用。
  3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。
  4. 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语言实现,我们会发现:

  1. 每个函数的第一个参数都是Stack*
  2. 函数中必须要对第一个参数检测,因为该参数可能会为NULL
  3. 函数中都是通过Stack*参数操作栈的
  4. 调用时必须传递Stack结构体变量的地址

  结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。

Cpp实现栈
观察C++实现,我们会发现:
  C++中通过类可以将** 数据 以及 操作数据的方法进行完美结合**,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要传递Stack的参数了,编译器编译之后该参数会自动还原,即C++中 Stack 参数是编译器维护的,C语言中需用用户自己维护


总结

  怎么样,本节内容开始有意思了起来,接下来的中篇会更有意思!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2144173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dcmtk在MWLSCP会忽略对于字符集的匹配

版本信息 dcmtk v3.6.4 2018-11-29 发现的原因 在我将dcmtk的wlmscpfs当作MWLSCP使用的时候&#xff0c;我在SCU端为了防止过来的数据中存在不识别的字符集&#xff0c;对于收到的数据数据进行了字符集的过滤&#xff0c;但是发现过滤没有生效。 确保数据源 首先需要确认数…

pywebview 中错误使用async

错误代码 正确示例 完整代码 前端代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>pywebview …

哈希表数据结构学习

哈希表数据结构学习 哈希表基本概念哈希方法单值哈希与多值哈希哈希冲突1. 开放寻址法&#xff08;Open Addressing&#xff09;2. 链地址法&#xff08;Chaining&#xff09;3. 再哈希法&#xff08;Rehashing&#xff09;4. 建立公共溢出区&#xff08;Overflow Area&#xf…

OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(下)

往期知识点记录&#xff1a; OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——轻量系统STM32F407芯片移植案例 OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——Combo解决方案之W800芯片移植案例 OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——小型系统STM32M…

『功能项目』窗口可拖拽脚本【59】

本章项目成果展示 我们打开上一篇58第三职业弓弩的平A的项目&#xff0c; 本章要做的事情是给坐骑界面挂载一个脚本让其显示出来的时候可以进行拖拽 创建脚本&#xff1a;DraggableWindow.cs using UnityEngine; using UnityEngine.EventSystems; public class DraggableWindo…

使用three.js+vue3完成无人机上下运动

效果图如上 代码&#xff1a; <template><div class"drones"><div ref"dronesContainer" class"drones-container"></div></div></template><script setup>import { ref, onMounted, onUnmounted, …

性能再升级,华为Mate 70 Pro曝光,设计新颖且配置遥遥领先

在智能手机市场竞争日益激烈的今天&#xff0c;各大厂商都在努力提升自家产品的性能和设计。 华为作为中国领先的手机品牌&#xff0c;一直备受关注。 近日&#xff0c;有关华为Mate 70 Pro的曝光信息引发了广泛关注&#xff0c;据悉&#xff0c;这款新机将在性能、设计和配置…

vue和thinkphp路由伪静态配置

vue路由伪静态配置&#xff1a; location / { try_files $uri $uri/ /index.html; } thinkphp 路由伪静态配置 location ~* (runtime|application)/{ return 403; } location / { if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s$1 last; break; } }

【Java】基础语法介绍

目录 一、注释 二、标识符与关键字 三、输入和输出 3.1 输出 3.2 输入 四、数据类型 3.1 基本数据类型 3.2 引用数据类型 3.3 var关键字 五、运算符 六、分支和循环 5.1 分支 5.2 循环 七、类和对象 6.1 类的定义与对象的创建 6.2 空对象 6.3 类的属性 6.4 类…

优化下载性能:使用Python多线程与异步并发提升下载效率

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 普通请求下载📝 使用多线程加速下载📝 使用异步编程加速下载📝 总结 📝⚓️ 相关链接 ⚓️📖 介绍 📖 你是否因为下载速度慢而感到焦虑?特别是在下载大型文件时,等待进度条慢慢移动的感觉真的很…

【Head-DETR系列(7)】DETR 代码分析

在nuscens数据集上&#xff0c; Results and Models BackboneModelLr schdMem (GB)Inf time (fps)box APConfigDownloadR-50DETR150e7.940.1configmodel | log 我们先看检测器 /mmdetection-2.28.2/mmdet/models/detectors/detr.py def forward_train(self,img,img_metas,gt_…

利基网站收入报告(更新至十月)

欢迎来到我的利基网站收入报告。这是我揭露当月我所有网站收入情况的地方。目前&#xff0c;我主要专注于一个核心网站&#xff0c;其余的不是重心&#xff0c;有些可能会在不久的将来出售。 为什么我分享我的利基网站收入报告&#xff1f; 需要旧报告&#xff1f; 2023年10月…

JSON包新提案:用“omitzero”解决编码中的空值困局

Go标准库是Go号称“开箱即用”的重要因素&#xff0c;而标准库中的encoding/json包又是标准库最常用的Go包。虽然其性能不是最好的&#xff0c;但好在由Go团队维护&#xff0c;对JSON规范兼容性好&#xff0c;且质量很高。但json包也不是没有“瑕疵”的&#xff0c;Go官方继mat…

6款SSL证书实用工具,格式转换/CSR生成等全都免费使用!

俗话说“工欲善其事&#xff0c;必先利其器”&#xff0c;SSL证书作为保护网站数据传输安全的重要部分&#xff0c;我们在申请、签发、部署安装SSL证书的时候&#xff0c;可能会涉及到CSR文件生成、获取证书链、转换证书格式等需求&#xff0c;这时候有对应的工具就可提高工作效…

基于SpringBoot的考研助手系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

干货| Python代码性能优化总结

代码优化原则 本文会介绍不少的 Python 代码加速运行的技巧。在深入代码优化细节之前&#xff0c;需要了解一些代码优化基本原则。 这里插播一条粉丝福利&#xff0c;如果你正在学习Python或者有计划学习Python&#xff0c;想要突破自我&#xff0c;对未来十分迷茫的&#xf…

超全网络安全面试题汇总(2024版)

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

P1079 [NOIP2012 提高组] Vigenère 密码------------------------------P1703 那个什么密码2

P1079 [NOIP2012 提高组] Vigenre 密码 题目描述 16 世纪法国外交家 Blaise de Vigenre 设计了一种多表密码加密算法 Vigenre 密码。Vigenre 密码的加密解密算法简单易用&#xff0c;且破译难度比较高&#xff0c;曾在美国南北战争中为南军所广泛使用。 在密码学中&#xff…

3DMAX道路生成器插件RoadGenerator使用方法详解

3DMAX道路生成器插件RoadGenerator&#xff0c;一键生成全模3DMax道路插件&#xff0c;是一款便捷且极受欢迎的参数化道路建模插件。RoadGenerator插件从样条线&#xff08;道路中心线&#xff09;快速创建道路系统。包括路面、行车线、双黄线、斑马线、箭头、路牙、人行道、路…

2024年某大厂HW蓝队面试题分享

&#x1f91f; 基于入门网络安全/黑客打造的资源包无偿分享中&#xff1a; &#x1f449;黑客&网络安全入门&进阶学习资源包 应急响应流程 1&#xff09;首先判断服务器资产、影响范围以及严重程度&#xff0c;确认有没有必要将服务器下线隔离&#xff0c;然后根据服务…