【C++】类与对象(一)

news2024/12/25 13:42:35

文章目录

  • 1、面向过程和面向对象初步认识
  • 2、类的引入
  • 3、类的定义
  • 4、类的访问限定符
  • 5、类的作用域
  • 6、类的实例化
  • 7、计算类对象的大小
  • 8、this指针
  • 9、 C语言和C++实现Stack的对比

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

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
举例子来理解一下就是,送外卖,先是商家做饭,打包,联系外卖员,外卖员取货,送货,联系买家,爬楼梯,敲门等。注重的是过程。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
举例子来理解一下就是,商家,外卖员,买家。注重对象。

2、类的引入

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

#nclude<stdlib.h>
#include<iostream>
using namespace std;

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 Push(const DataType& data)
	{
		// 扩容
		_array[_size] = data;
		++_size;
	}
	DataType Top()
	{
		return _array[_size - 1];
	}
	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
	DataType* _array;
	size_t _capacity;
	size_t _size;
};
int main()
{
	Stack s;
	s.Init(10);
	s.Push(1);
	s.Push(2);
	s.Push(3);
	cout << s.Top() << endl;
	s.Destroy();
	return 0;
}

在上面的结构体定义,在C++当众更加的喜欢使用class
C++中有structclass创建结构体(创建对象)两种方法,从下面的代码当中可以了解到在结构体当中在次调用struct必须要带上structclass就不需要。

struct List1
{
	struct List1* arr;
};

class List2
{
	List2* ret;
};

3、类的定义

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

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

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

一般情况下,更期望采用第二种方式。
下面简单介绍一下成员变量(类的属性)的命名问题。
就是在声明成员变量的时候在变量名前加_,防止在定义和赋值时的出现问题。当然在这里使用其他的方法也是行的。

class Date
{
public:
	void Init(int year, int month, int day)
	{
		year = year;//err
	}
private:
	int year;
	int month;
	int day;
};
class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;//ture
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

4、类的访问限定符

在这里插入图片描述

【访问限定符说明】

    1. public修饰的成员在类外可以直接被访问
    1. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
    1. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
    1. 如果后面没有访问限定符,作用域就到 } 即类结束。
    1. class的默认访问权限为private,struct为public(因为struct要兼容C)
      注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

5、类的作用域

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

class Date
{
public:
	void Init(int year, int month, int day);
private:
	int _year;
	int _month;
	int _day;
};
//要指定该函数是在哪个类当中声明的。
void Date::Init(int year, int month, int day)//注意
{
	_year = year;//ture
	_month = month;
	_day = day;
}

6、类的实例化

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

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
class Date
{
public:
	void Init(int year, int month, int day);
private:
	int _year;
	int _month;
	int _day;
};
void Date::Init(int year, int month, int day)
{
	_year = year;//ture
	_month = month;
	_day = day;
}

int main()
{
	Date a;
	a.Init(1,1,1);
	return 0;
}

Date类是没有空间的,只有Date类实例化出的对象才有具体的时间。
3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
只有在类的实例化时才会为类中的变量开空间,成员变量是在类当中开辟空间的,而成员函数并不是在类中开辟空间,所以在类的实例化时只会只需要开辟成员变量的空间。

为什么成员变量在对象当中,而成员函数却不在对象当中?
1、每个对象中的成员变量都是不一样的,需要独立储存。
2、每个对象调用成员函数都是一样的,放在共享公共空间(代码段)

7、计算类对象的大小

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

A1:4 A2:1 A3:1
结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
注意空类的大小,空类比较特殊,占位,编译器给了空类一个字节来唯一标识这个类的对象。

8、this指针

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函
数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成。

下面代码是系统将透明的代码显示出来的样子,从下面的图片中也可以看出this用于区分不同对象。

#include<iostream>
using namespace std;
class Date
{
public:
	void Init(Date* this, int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1, d2;
	d1.Init(&d1, 2022, 1, 11);
	return 0;
}

在这里插入图片描述

指针的特性

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

在上文当中提到了成员函数(类的方法)存放在代码段当中,但是不要和函数参数和临时变量存放的方法混淆,他们是存放在栈区。
接下来我么们来考虑两个问题

  1. this指针存在哪里?
    因为在计算类对象大小的时候,只是计算了成员变量的大小,所以并没有给this指针开辟空间。
    this指针存放在栈区(vs当中存放在ecx寄存器当中)
  2. this指针可以为空吗?
    从下面的代码中也是可以看出看到空指针解引用就是错误的,而是要看调用的对象当中是否有解引用的操作。
#include<iostream>
using namespace std;
class Date
{
public:
	void Init(int year, int month, int day)
	{
		cout << this << endl;
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
	void func()
	{
		cout << this << endl;
		cout << "func()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date* p = nullptr;
	p->func();           //正常运行
	p->Init(2023,3,1);   //程序崩溃
	(*p).func();         //正常运行
	return 0;
}

9、 C语言和C++实现Stack的对比

c语言
可以看到,在用C语言实现时,Stack相关操作函数有以下共性:

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

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

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

最后:文章有什么不对的地方或者有什么更好的写法欢迎大家在评论区指出

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

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

相关文章

算法练习-排序(一)

算法练习-排序(一) 文章目录算法练习-排序(一)1 排序算法1.1 冒泡排序1.1.1代码1.2插入排序1.2.1代码1.3 选择排序1.3.1代码1.4归并排序1.4.1代码1.5 快速排序1.5.1 思路1.5.2 代码2 题目2.1 特殊排序2.1.1 题目2.1.2 题解2.2 数组中的第k个最大元素2.2.1 题目2.2.2 题解2.3 对…

【Linux学习】基础IO——系统调用 | 文件描述符fd | 重定向

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 基础IO&#x1f34e;文件操作&#x1f349;使用C接口进行文件操作&#x1f349;文件操作的系统调…

Ingress

Ingres 目录 文章目录Ingres目录本节实战1、Ingress是什么2、定义1.rules2.Resource3.pathType4.IngressClass5.TLS3、Ingress-controller1.什么是Ingress-controller2.其他ingress-controller控制器FAQ零碎ingress就是借用service实现服务发现机制关于我最后本节实战 无 1、…

MySQL基础(一)SQL分类、导入、SELECT语句,运算符

目录 MySQL安装以及相关工具 SQL分类 导入数据 最基本的SELECT语句 SELECT FROM 列的别名 去除重复行 着重号 查询常数 描述表结构 过滤数据&#xff08;重要&#xff09; 运算符 算数运算符 比较运算符 符号运算符 非符号运算符 逻辑运算符 位运算符 MySQL安…

【C++】继承与多态

目录前言1. 继承1.1 继承的概念1.2 继承的定义1.3 切片赋值1.4 继承中的作用域1.5 派生类的默认成员函数1.6 继承与友元、静态成员1.7 多继承、菱形继承、菱形虚拟继承1.7.1 区分单继承与多继承1.7.2 菱形继承1.7.3 菱形虚拟继承1.7.4 菱形虚拟继承的原理2. 多态2.1 概念2.2 多…

Elasticsearch实战之(商品搜索API实现)

Elasticsearch实战之&#xff08;商品搜索API实现&#xff09; 1、案例介绍 某医药电商H5商城基于Elasticsearch实现商品搜索 2、案例分析 2.1、数据来源 商品库 - 平台运营维护商品库 - 供应商维护 2.2、数据同步 2.2.1、同步双写 写入 MySQL&#xff0c;直接也同步往…

如何使用C2concealer生成随机化的C2 Malleable配置文件

关于C2concealer C2concealer是一款功能强大的命令行工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以轻松生成随机化的C2 Malleable配置文件&#xff0c;以便在Cobalt Strike中使用。 工具运行机制 开发人员对Cobalt Strike文档进行了详细的研究&#xff0c;…

【转载】2020融云:基于WebRTC的低延迟视频直播

原文直接访问本文是读书笔记。基于WebRTC的低延迟视频直播 需要学习rtp包的缓存设计,于是找到了这一篇文章rtp包缓存 如何适应直播需求?直播与实时通信的区别 流量更少: RTMP或者HLS主要基于TCP传输,WebRTC是基于UDP的传输, **UDP协议的头小。**TCP为了保证传输质量,因…

Zotero设置毕业论文/中文期刊参考文献格式

大家在使用zotero时很容易遇到的问题&#xff1a; 英文参考文献中有多个作者时出现“等”&#xff0c;而不是用"et al"引文最后面有不需要的DOI号&#xff0c;或者论文链接对于一些期刊分类上会出现OL字样&#xff0c;即[J/OL]作者名为全大写 本文主要解决以上几个…

string函数以及string常用接口

本文介绍的是C关键字string中一些重要用法&#xff0c;以及各种字符串序列的处理操作 ——飘飘何所似&#xff0c;天地一沙鸥 文章目录前言一、string&#xff08;字符串类&#xff09;二、string类对象的容量操作2.1 size/length2.2 capacity2.3 empty/clear2.4 resize/reser…

教你如何搭建设备-保养管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建设备-保养管理。1.2、应用场景设备管理员进行制定设备保养计划、记录设备保养信息、可以查看设备保养日历。2、设置方法2.1、表单搭建1&#xff09;新建表单【设备档案-履历表】&#xff0c;字段设置如下&#xff1a;名称类…

SSM SpringBoot vue 在线教学质量评价系统

SSM SpringBoot vue 在线教学质量评价系统 SSM 在线教学质量评价系统 功能介绍 首页 图片轮播展示 登录 学生注册 教师注册 督导注册 教师展示 教师详情 学生评价 课程信息 课程详情 提交选修该课 学生选课 学生留言 个人中心 后台管理 管理员或学生或教师或督导登录 个人中…

项目经理处理团队冲突 5大注意事项

1、在时间、场景、体验矩阵中的5种处理方式 第一种方式&#xff1a;强迫命令&#xff0c;即职位高的一方在不考虑对方感受的情况下&#xff0c;强迫职位低的一方接受自己的意见。这种处理方式的适用场景为重要且紧急&#xff0c;这种方式团队成员的体验感低。 第二种方式&#…

Linux 学习笔记(一):终端 和 Shell 的区别和联系

一、Linux 介绍 1、什么是 Linux Linux 就是一个操作系统&#xff0c;全称 GNU/Linux&#xff0c;是一种类 Unix 操作系统Linux 一开始是没有图形界面的&#xff0c;所有操作都靠 命令 完成。如 磁盘操作、文件存取、目录操作、进程管理、文件权限 等等&#xff0c;可以说 Li…

Android Handler机制(二) Handler 实现原理

一. 前言 接上一篇文章为什么设计Handler , 我们来继续讲解一下Handler的实现原理, 俗话说一个好汉三个帮, 接下来一步一步引入各个主角,并说明它们在Handler机制中扮演的角色和作用. 二. Handler实现原理 首先我们先确定一个结论: 使用 Handler 是希望它被实例化在哪个线程&a…

不同序列模型的输入和输出总结

不同序列模型的输入和输出总结 文章目录不同序列模型的输入和输出总结RNNLSTMGRURNN RNN 是迭代输出&#xff1a; 输入第一个 -> 输出第二个&#xff0c; 输入第二个 -> 输出第三个&#xff0c; 输出倒数第二个 -> 输出最后一个。 LSTM LSTM 也是迭代输出&#xff…

Ep_操作系统面试题-什么是协程

协程 是一种 比线程更加轻量级的存 在&#xff0c;一个线程可以拥有多个协程。是一个特殊的 函数 &#xff0c;这个函数可以在某个地方挂起&#xff0c;并且可以重新在挂起处外继续运行。协程 不是被操作系统内核所管理 &#xff0c; 而完全是由程序所控制&#xff08;也就是在…

冯诺依曼体系结构与操作系统的理解

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;操作系统 &#x1f4ac;<3>前言&#xff1a;今天来介绍一下冯诺依曼体系结构&#xff0c;和操作系统的理解。 目录 1.冯诺依曼体系结构 冯诺依曼体系的工作原理&#xff1a; 为…

注意力机制详解系列(四):混合注意力机制

👨‍💻作者简介: 大数据专业硕士在读,CSDN人工智能领域博客专家,阿里云专家博主,专注大数据与人工智能知识分享。 🎉专栏推荐: 目前在写CV方向专栏,更新不限于目标检测、OCR、图像分类、图像分割等方向,目前活动仅19.9,虽然付费但会长期更新,感兴趣的小伙伴可以…

超详细Eclipse配置JDK

在此附上Eclipse安装教程 超详细Eclipse安装教程 在此附上JDK1.8安装配置教程 超详细JDK1.8安装与配置 ①打开Eclipse–>点击Window–>点击Preferences ②找到Java–>找到Installed JREs–>点击Add… ③选中Standard VM–>之后点击Next ④点击Directory找…