类和对象(—)

news2024/12/23 22:56:06

今天,我带来类和对象的基础篇。



目录

    • 面向对象和面向过程
      • 类的概念
      • 类的定义
      • 类的访问限定符
      • c++中struct和class的区别
      • 封装
      • 类的作用域
      • 类的实例化
      • 类的存储
      • 结构体内存对齐规则
      • 【面试题】
      • this指针
        • this指针的概念
        • this指针的特性
      • 【面试题】



面向对象和面向过程

C语言是面向过程的,关注的是过程。
C++是基于面向对象的,关注的是对象。

比如:现在我要写一个点餐的小程序,那么,c语言出发,就是逐步分析,写出了许多的函数,不管是客户端还是服务端,都是通过这一堆的函数调用逐步解决问题的,面向的是过程。
c++出发,就可以使用下面提到的类,创建两个类,一个是服务端的类,一个是客户端的类,关注的是对象,靠对象之间的交互完成。



类的概念

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
比如:

typedef int DataType;
struct Stack
{
	void Init(size_t capacity)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
		void Destroy()
		{
			if (_array)
			{
				free(_array);
				_array = nullptr;
				_capacity = 0;
				_size = 0;
			}
		}
		DataType* _array;
		size_t _capacity;
		size_t _size;
};

C++中更喜欢用class来代替struct。

类的定义

class className
{
// 类体:由成员函数和成员变量组成
};

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

类的两种定义方式:

  1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
typedef int DataType;
class Stack
{
	void Init(size_t capacity)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
	DataType* _array;
	size_t _capacity;
	size_t _size;
};
  1. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::

test.h文件:

typedef int DataType;
class Stack
{
	void Init(size_t capacity);
	void Destroy();

	DataType* _array;
	size_t _capacity;
	size_t _size;
};

test.cpp文件中:

#include"test.h"

void Stack::Init(size_t capacity)
{
	_array = (DataType*)malloc(sizeof(DataType) * capacity);
	if (nullptr == _array)
	{
		perror("malloc申请空间失败");
		return;
	}
	_capacity = capacity;
	_size = 0;
}
void Stack::Destroy()
{
	if (_array)
	{
		free(_array);
		_array = nullptr;
		_capacity = 0;
		_size = 0;
	}
}

推荐第二种。

关于成员变量的命名。

// 我们看看这个函数,是不是很僵硬?
class Date
{
public:
 	void Init(int year)
 	{
		 // 这里的year到底是成员变量,还是函数形参?
		 year = year;
 	}
private:
	 int year;
};

如上,year变量难以区分,虽然后面有this指针来引用成员变量的year,但是每一个赋值都要写this指针,有点不方便。

class Date
{
public:
	 void Init(int year)
	 {
 		_year = year;
	 }
private:
	 int _year;
};

成员变量直接加上一个_,就容易区分的多了,其他方式也可以,如加一个前缀或者后缀。

类的访问限定符

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

访问限定符:

public(公有)
protected(保护)
private(私有)

【访问限定符说明】

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

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

c++中struct和class的区别

C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。

封装

面向对象的三大特性:封装、继承、多态。

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装本质上是一种管理,让用户更方便使用类。

在C++语言中实现封装,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中,即类的{};里面。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。

如:
test.h文件:

typedef int DataType;
class Stack
{
	void Init(size_t capacity);
	void Destroy();

	DataType* _array;
	size_t _capacity;
	size_t _size;
};

test.cpp文件中:

#include"test.h"

void Stack::Init(size_t capacity)//在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
{
	_array = (DataType*)malloc(sizeof(DataType) * capacity);
	if (nullptr == _array)
	{
		perror("malloc申请空间失败");
		return;
	}
	_capacity = capacity;
	_size = 0;
}
void Stack::Destroy()//在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
{
	if (_array)
	{
		free(_array);
		_array = nullptr;
		_capacity = 0;
		_size = 0;
	}
}

类的实例化

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

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
class Student
{
public:
	long long StudentNum;//学号
	int weight;//体重
	int height;//身高
};

int main()
{
	//Person.height = 185;//错误演示,报错提示:error C2059: 语法错误:“.”

	Person* p = new Person;//正确写法,先实例化
	p->height = 185;
	return 0;
}

类的存储

代码只保存一份,在对象中保存存放代码的地址。
只保存成员变量,成员函数存放在公共的代码段

代码作为公共部分,所以只需要一份就行。每个的类的成员变量的值不相同,所以要各自存一份。

验证一下:

// 类中既有成员变量,又有成员函数
class A1 {
public:
	void f1() {}
private:
	int _a;
};

// 类中仅有成员函数
class A2 {
public:
	void f2() {}
};
// 类中什么都没有---空类
class A3
{};

int main()
{
	cout << "A1 : " << sizeof(A1) << "  ";
	cout << "A2 : " << sizeof(A2) << "  ";
	cout << "A3 : " << sizeof(A3) << endl;
	return 0;
}

在这里插入图片描述
结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐

注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

结构体内存对齐规则

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

【面试题】

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

this指针

this指针的概念

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

如:

// 我们看看这个函数,是不是很僵硬?
class Date
{
public:
 	void Init(int year)
 	{
		 // 这里的year到底是成员变量,还是函数形参?
		 year = year;
 	}
private:
	 int year;
};

上面提到的year名称难以方便的问题,除了在成员变量加前缀或者后缀来识别外,还可以使用this指针。

class Date
{
public:
	void Init(int year)
	{
		this->year = year;
	}
private:
	int year;
};

this指针的特性

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

【面试题】

  1. this指针存在哪里?

栈,因为他是隐含形参。

  1. this指针可以为空吗?

可以,只要不进行解引用就行。

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();//正常运行,因为调用的Print函数不在对象里,而在代码块中,所以没有对p即空指针就行解引用
	return 0;
}
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->PrintA();//运行崩溃,因为Print函数虽然在代码块中,不在对象中,但函数中的_a是在对象中,所以会对p即空指针就行解引用
	return 0;
}

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

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

相关文章

[PyTorch][chapter 44][时间序列表示方法3]

简介: word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包&#xff0c;它简单、高效&#xff0c;因此引起了很多人的关注。由于 word2vec 的作者 Tomas Mikolov 其主要知识点 目录&#xff1a; word2vec 基本思想 Skip-gram cbow Hierarchical sof…

MedNeXt的一些问题集锦

归纳偏差是一种关于机器学习算法的目标函数的假设&#xff0c;也就是目标函数评分的标准。 归纳偏差是指模型更容易学习到训练数据中的局部和表面特征&#xff0c;而较难捕捉全局和抽象特征。 scalable 可扩展的 network-wide优势&#xff1f;&#xff1f;&#xff1f; 深度监…

(论文精读)PRUNING FILTER IN FILTER《滤波器中的剪枝滤波器》

论文地址&#xff1a;原文 代码实现 中文翻译 一、精读论文 论文题目 PRUNING FILTER IN FILTER 论文作者 Fanxu Meng 孟繁续 刊物名称 NeurIPS 2020 出版日期 2020 摘要 剪枝已成为现代神经网络压缩和加速的一种非常有效的技术。现有的剪枝方法可分为两大类:滤波器…

MVC三层架构

1.MVC三层架构 MVC&#xff08;Model-View-Controller&#xff09;是一种常见的软件设计模式&#xff0c;用于组织和管理应用程序的代码和逻辑。它将应用程序分为三个主要部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#…

营销同质化,博鱼 sports牵手那不勒斯打开新大门

体育营销是企业进入新市场的经典方式&#xff0c;特别是对当今寻求高质量发展的国产品牌而言&#xff0c;从产品出海升级为品牌出海&#xff0c;体育营销可谓是一条必经之路。海信、OPPO、华为等中国品牌通过持续的体育营销不断拉近自身与海外消费者的距离&#xff0c;成功在海…

反常积分定义

目录 反常积分的定义 判断敛散性的方法 方法2&#xff1a; 例题 无界函数的反常积分 判断敛散性的方法 例题 反常积分的定义 该极限存在就表示该反常积分收敛 对于定义3&#xff0c;只有两个都收敛的情况下&#xff0c;原反常积分才收敛。 判断敛散性的方法 始终大的函数形成…

走进USB的U1模式

综述&#xff1a; PCIE有PM和ASPM两种功耗管理模式&#xff0c;USB只有一种 USB有U1/U2/U3三种低功耗模式 本文只针对U1进行分析 如下图所示&#xff0c;为主要状态变换 背景知识 U1是一种低功耗模式&#xff0c;定义的是link的状态不是设备的状态发送LGO_X进入低功耗模式&a…

C++图形开发(12):随机方块的速度和高度

文章目录 1.随机高度2.随机速度3.整段代码4.总结 1.随机高度 那既然是随机&#xff0c;自然少不了随机函数rand()咯~ 详见&#xff1a;C爱好者的自我修养&#xff08;17&#xff09;:rand()随机函数 那么随机速度就可以是&#xff1a; rect_height rand() % int(height / 4)…

【在 WSL2 GUI 中使用 pulseaudio 播放声音】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pulseaudio 是什么&#xff1f;二、部署步骤1.下载PulseAudio2.前提条件3.开始配置1.配置pulseaudio2.配置麦克风权限3.配置WSL2外放4.配置WSL2麦克风 总结…

hbase之引入Phoenix

Phoenix简介 Phoenix是HBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表&#xff0c;插入数据和查询HBase数据。 1&#xff09;容易集成&#xff1a;如Spark&#xff0c;Hive&#xff0c;Pig&#xff0c;Flume和Map Reduce&#xff1b; 2&#xf…

RocketMQ5.0消息存储<四>_刷盘机制

RocketMQ5.0消息存储<四>_刷盘机制 一、刷盘概览 RocketMQ存储与读写是基于JDK NIO的内存映射机制(MappedByteBuffer),消息存储时首先将消息追加到文件内存映射(commit操作),再根据配置的刷盘策略在不同时间进行刷写到磁盘(flush操作)。同步刷盘,消息提交到文件内…

计算机实习学习总结报告10篇

计算机实习学习总结报告篇1 一、实习单位&#xff1a; 来到实习单位后主要是在门市从事产品的销售和商家间渠道工作。在工作的过程中了解计算机相关行业的发展现状及趋势;熟悉计算机硬件组装、计算机系统及软件安装、局域网搭建;掌握典型计算机网络工程的安装与维护;了解网站…

Linux之Shell进阶(变量和条件判定语句)

文章目录 变量变量的含义变量的定义与使用&#xff08;重点&#xff09;只读变量接收用户输入删除变量 条件判断语句 变量 变量的含义 什么是量&#xff1f; 量就是数据. 什么是变量&#xff1f; 数据可以发生改变就是变量。 在一个脚本周期内,其值可以发生改变的量就是变…

python调用钉钉发送告警消息

zabbix和prometheus都能做监控告警调用企业微信和钉钉。那么问题来了做为一名合格的运维和开发人员&#xff0c;脚本发现故障告警&#xff0c;自动调用发送详细告警内容&#xff0c;这点儿东西得会。 效果图如下&#xff1a; 普通发送方式 import requestsdef dingding_info(…

AR 技术应用与管理解决方案:施工建造、机柜扫描、办公室导航

建筑行业作为人类历史上最重要的产业之一&#xff0c;在数字化转型方面同样也在不断推进。图扑软件结合 AR 技术的应用&#xff0c;为建筑行业带来了更加便捷高效的建筑施工过程管理。 传统的建筑施工管理过程中&#xff0c;由于缺乏信息化手段&#xff0c;往往存在资料不全、…

解决microsoft windows 恶意软件删除工具 占用内存高

1、winR快捷键&#xff0c;输入regedit&#xff0c;按回车键进入注册表编辑器 2、定位到 \HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\ 并创建新项MRT 3、 新建DWORD(32)值&#xff0c;命名为DontOffer ThroughWUAU,数值数据为1; 4、以管理员身份运行命令提示符&#x…

vue3的customRef

文章来源:我的博客,欢迎访问,不欢迎攻击,谁攻击谁儿子 customRef 作用:实现一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制 像是下面的代码一样: <template><div class"lim"><div class"btns"><el-input type"text…

web期末作业(html+css)-中华美食介绍(附带文档)

作品展示 web期末作业-中华美食介绍 首页包含功能&#xff1a; 轮播图&#xff1a;在首页顶部设置一个可自动轮播的图片展示区域&#xff0c;展示多张宣传图片或产品图片&#xff0c;提升页面的视觉效果和吸引力。 鼠标滑过文字变色&#xff1a;为首页的一些关键文字或链接添…

python安装opencv出错 PEP 517

我的 python 版本是 3.6 的&#xff0c;当需要安装 opencv 时&#xff0c;使用pip install opencv-python 命令进行安装时&#xff0c;出现错误&#xff0c;如下所示&#xff1a; Building Custom Rule C:/Users/liqian/AppData/Local/Temp/pip-install-6jpavinn/opencv-pytho…

element 树形表格每次刷新列表保存展开关闭状态

树形表格保存展开关闭状态 编辑数据后&#xff0c;记录用户操作行的展开和关闭 注意&#xff0c;以下列子是默认展开&#xff0c;记录合上的状态 注意 row-key 需要给每行一个key expand-change 点击行的操作 <el-tableref"tableItem"slot"table":data…