c++初阶-------类和对象

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


类与对象

  • **作者前言**
  • 面向对象和面向对象的认识
  • 类的引入
    • 类的定义
    • 访问限定符
    • 类的方法声明和定义分离
    • 封装
      • 类的作用域
      • 类的实例化
    • 类的大小
      • 类的存储方式的猜测
      • 类的大小的特殊情况
    • this 指针
      • this的介绍
      • C语言和C++实现Stack的对比

面向对象和面向对象的认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
就拿洗衣服来说
在这里插入图片描述
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完
成。
在这里插入图片描述

类的引入

我们知道C语言的struct的结构体只能定义变量,不能定义函数,所以我们只能在结构体外定义,但在c++中不仅继承了C语言的struct的所有用法,还补充了C语言结构体不能定义函数的用法

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
struct SList
{
	int* a;
	int top;
	int capacity;
	//插入
	void Push(int x)
	{
		if (top == capacity)
		{
			//扩容
			int t = capacity > 0 ? 2 * capacity : 4;
			int* tmp = (int*)realloc(a, sizeof(int) * t);
			if (tmp == NULL)
			{
				perror("ralloc");
				return;
			}
			capacity = t;
			a = tmp;
		}
		a[top] = x;
		top++;
	}
	//初始化
	void Init()
	{
		a = NULL;
		top = 0;//栈底元素下一个
		capacity = 0;
	}
	//删除
	void Pop()
	{
		top--;
	}
};
int main()
{
	SList stack;
	stack.Init();
	stack.Push(4);
	stack.Push(3);
	stack.Push(2);
	stack.Push(1);
	stack.Pop();
	return 0;
}

类的定义

相比于struct定义类,c++更喜欢使用class来定义

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

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

访问限定符

类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
在这里插入图片描述
访问限定符有三种 public、protected private

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class SList
{
protected:
	int* a;
	int top;
	int capacity;
public:
	//插入
	void Push(int x)
	{
		if (top == capacity)
		{
			//扩容
			int t = capacity > 0 ? 2 * capacity : 4;
			int* tmp = (int*)realloc(a, sizeof(int) * t);
			if (tmp == NULL)
			{
				perror("ralloc");
				return;
			}
			capacity = t;
			a = tmp;
		}
		a[top] = x;
		top++;
	}
	//初始化
	void Init()
	{
		a = NULL;
		top = 0;//栈底元素下一个
		capacity = 0;
	}
	//删除
	void Pop()
	{
		top--;
	}
};
int main()
{
	SList stack;
	stack.Init();
	stack.Push(4);
	stack.Push(3);
	stack.Push(2);
	stack.Push(1);
	stack.Pop();



	return 0;
}

【访问限定符说明】

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

类的方法声明和定义分离

在类中,函数的定义有两种,
一种是在类的内部进行定义,编译器可能会将其当成内联函数处理。相当于函数被inline修饰了,至于会不会被展开,由编译器决定的>。
上面的代码就是在类的内部定义的

另一种就是在头文件里面声明,然后在其他cpp文件定义
头文件

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class SList
{
protected:
	int* a;
	int top;
	int capacity;
public:
	void Push(int x);
	void Init();
	//删除
	void Pop()
	{
		top--;
	}
};

cpp文件

#include"day2_1.h"
//插入
void SList::Push(int x)
{
	if (SList::top == capacity)
	{
		//扩容
		int t = capacity > 0 ? 2 * capacity : 4;
		int* tmp = (int*)realloc(a, sizeof(int) * t);
		if (tmp == NULL)
		{
			perror("ralloc");
			return;
		}
		capacity = t;
		a = tmp;
	}
	a[top] = x;
	top++;
}
//初始化
void SList::Init()
{
	a = nullptr;
	top = 0;//栈底元素下一个
	capacity = 0;
}
int main()
{
	SList stack;
	stack.Init();
	stack.Push(4);
	stack.Push(3);
	stack.Push(2);
	stack.Push(1);
	stack.Pop();
	return 0;
}

函数里面的变量会先在当前的{}里面找,找不到就会去对应的类里面找

我们在看到很多人写的c++代码里面的成员很多都会加 -

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

封装

C++中的封装是面向对象编程的特性之一,它允许将数据和操作封装在类的内部,对外部隐藏实现细节。通过使用访问修饰符(public、private、protected),可以控制类成员的访问权限,实现数据的安全性和可控性。

类的作用域

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

类的实例化

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 data;
	data.Init(2024, 1, 1);
}

当我们使用这个类来创建一个变量,就是实例化对象

一个类可以实例化很多个对象

类的大小

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
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 data;
	data.Init(2024, 1, 1);
	Date data1;
	data1.Init(2024, 1, 1);
	Date data2;
	data2.Init(2024, 1, 1);
	cout << sizeof(Date);


}

在这里插入图片描述
可以发现类的大小是12,所以可以说明,类的方法的大小在类中不计算(内存对齐)
在这里插入图片描述

在反汇编中我们可以看到,不同对象的类的方法的地址是一样的,而不同对象的成员是不一样的,

类的存储方式的猜测

我们假设一下:
1.每创建一个对象,都会保存对应成员的所有代码(我们可以想象就是为类函数和成员变量都开辟空间
在这里插入图片描述
这样给内存造成了很大的浪费,
2. 每创建一个对象,都会保存类的成员变量的空间和类的方法的地址(简单的理解就是开辟成员变量的空间和存储对应类的方法的地址)
在这里插入图片描述
3. 类只保存成员变量的大小,成员函数存放在公共区域
在这里插入图片描述

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class Ta
{
public:
	void Fun()
	{

	}
private:
	int _a;
};
int main()
{
	Ta var;
	cout << sizeof(var);
	return 0;
}

在这里插入图片描述
这种情况可以说明,类的储存的情况是按照第三种来的,多个对象调用同名类成员函数是同一个函数

类的大小的特殊情况

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class Ta
{
};
int main()
{
	Ta var;
	cout << sizeof(var);
	return 0;
}

在这里插入图片描述

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class Ta
{
public:
	void Fun()
	{

	}
};
int main()
{
	Ta var;
	cout << sizeof(var);
	return 0;
}

在这里插入图片描述
这里涉及的知识有点多,后面讲解
准确的说,成员变量存在对象里面,其他的成员不是

this 指针

上面可能就会有疑问,不同的对象的成员变量不同,但是成员函数是相同的,那这个成员函数怎么区分这些成员变量是来自哪个对象的呢

#include<iostream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
class Ta
{
public:
	void Fun()
	{
		cout << _a << endl;
	}
	void Fun(Ta * _this)
	{
		cout << _this->_a << endl;
	}
public:
	int _a;
};
int main()
{
	Ta var;
	cout << sizeof(var)<<endl;
	var._a = 10;
	var.Fun();
	var.Fun(&var);
	return 0;
}

在这里插入图片描述

在这里插入图片描述
再结合我们之前的C语言写一个栈的时候,要传一个结构体的地址,而在c++可以不用,是因为c++编译器做了很多的步骤,就是解决了传结构体的地址的这个步骤

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

this的介绍

上面我们知道,类的成员函数都有一个隐藏的this指针
头文件:

include<iostream>
using std::cout;
using std::endl;
using std::cin;

class Data
{
public:
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
		cout <<this-> _year << "-" << this->_month << "-" << this->_day << endl;
	}
	void priyear();
	void Init(int year, int month, int day);


private:
	int _year;
	int _month;
	int _day;

};

cpp文件

void Data::priyear()
{
	cout << this->_year << endl;
}
void Data::Init(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}
int main()
{
	Data time1;
	Data time2;
	time1.Init(2024,1,1);
	time2.Init(2024, 1, 2);
	time1.Print();
	time2.Print();
	return 0;
}

在这里插入图片描述
一般我们不会写出this这个指针,新手可以写出来熟悉一下
注意一下: this指针不是存在对象里面的,(前面我们计算类的大小,只包括成员变量,不包括this指针,所以可以说 this指针不是存在对象里面的)

准确的说this就是一个形参,形参是存放在栈帧上面的,所以this存在于栈帧

小练习

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

这道题正常运行,前面我们学习了类的大小,知道类的成员函数是存储在公共区域的,并且函数地址也不在类中,调用类的成员函数,是在链接的符号表进行寻找的,然后找到对应的地址去进行运行,
写这个"p->PrintA();"是为了表明这个函数出自A这个结构体,而实际不存在类中
在这里插入图片描述
在字符表找到地址就是红框里面的

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

这个会报错,因为this是空指针,成员变量存放在类里面,需要通过类的指针进行访问

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

我们在C语言中,我们使用结构体成员,我们要一般通过写一个函数传入该结构体变量的地址进行访问
C语言版

#include<stdio.h>
#include<stdlib.h>
struct Stack
{
	int* arr;
	int top;//栈顶元素的下一个
	int capacity;
};
void Init(struct Stack* obj)
{
	obj->arr = (int*)malloc(sizeof(int) * 3);
	obj->top = 0;
	obj->capacity = 3;
}
int main()
{
	struct Stack sta;
	Init(&sta);


	return 0;
}

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

c++版

#include<iostream>
using std::cout;
using std::endl;
using std::cin;
class Stack
{
public:
	void Init()
	{
		arr = (int*)malloc(sizeof(int) * 3);
		top = 0;
		capacity = 3;
	}
private:
	int* arr;
	int top;//栈顶元素的下一个
	int capacity;
};

int main()
{
	Stack sta;
	sta.Init();
	return 0;
}

c++这里不用传结构体变量的指针,因为编译器帮我们搞定了
C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在
类外可以被调用,即封装
C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

以问答的方式解释编译器与解释器

编译器 编译器是什么&#xff1f; 编译器是一种计算机程序&#xff0c;它可以将源代码转换成目标代码。编译器通常包括一个词法分析器、一个语法分析器和一个代码生成器。 编译器将源代码转换为可执行的目标代码&#xff0c;可以在计算机上运行。编译器通常还负责优化生成的代码…

polar CTF web 被黑掉的站

一、题目 二、解答 1、dirsearch 扫目录 看到shell.php和index.php.bak 一看就是爆破&#xff0c;字典都给了&#xff0c;最后得到为 nikel

【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念 1、定义 二叉搜索树&#xff0c;又称为二叉排序树&#xff0c;二叉查找树&#xff0c;它满足如下四点性质&#xff1a; 1&#xff09;空树是二叉搜索树&#xff1b; 2&#xff09;若它的左子树不为空&#xff0c;则左子树上所有结点的值均小于它根结…

2023年终总结与展望

2023年终总结 自2019年3月13日入驻CSDN&#xff0c;至今四年零九个月。截至2023年12月31日&#xff0c;CSDN博客已发原创博文120篇&#xff0c;粉丝9822位&#xff0c;访问量超过176万次。 2022年12月31日数据情况&#xff1a; 2023年12月31日数据情况&#xff1a; 从 年终数…

跟着cherno手搓游戏引擎【2】:日志系统spdlog和premake的使用

配置&#xff1a; 日志库文件github&#xff1a; GitHub - gabime/spdlog: Fast C logging library. 新建vendor文件夹 将下载好的spdlog放入 配置YOTOEngine的附加包含目录&#xff1a; 配置Sandbox的附加包含目录&#xff1a; 包装spdlog&#xff1a; 在YOTO文件夹下创建…

再见2023,你好2024(附新年烟花python实现)

亲爱的朋友们&#xff1a; 写点什么呢&#xff0c;我已经停更两个月了。2023年快结束了&#xff0c;时间真的过得好快&#xff0c;总要写点什么留下纪念吧。这一年伴随着许多挑战和机会&#xff0c;给了我无数的成长和体验。坦白说&#xff0c;有时候我觉得自己好像是在时间的…

一起学docker(四)| 数据卷 + 简单应用部署(MySQL,Tomcat,Nginx,Redis)

Docker 容器数据卷 Docker容器产生的数据&#xff0c;如果不备份&#xff0c;那么当容器实例删除后&#xff0c;容器内的数据也就消失了。需要对数据进行持久化。 为了保存docker中的数据&#xff0c;可以使用数据卷。 是什么 卷就是目录或文件&#xff0c;存在于一个或多个…

HUAWEI华为荣耀MagicBook X 15酷睿i5-10210U处理器集显(BBR-WAH9)笔记本电脑原装出厂Windows10系统

链接&#xff1a;https://pan.baidu.com/s/1YVcnOP5YKfFOoLt0z706rg?pwdfwp0 提取码&#xff1a;fwp0 MagicBook荣耀原厂Win10系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、华为/荣耀电脑管家等预装程序 文件格式&#xff1a;esd/wim/swm 安装…

深度学习|10.5 卷积步长 10.6 三维卷积

文章目录 10.5 卷积步长10. 6 三维卷积![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b5bfa24f57964b0f81f9602f5780c278.png) 10.5 卷积步长 卷积步长是指每计算一次卷积&#xff0c;卷积移动的距离。 设步长为k&#xff0c;原矩阵规模为nxn&#xff0c;核矩阵…

Python 实现给 pdf 文件自动识别标题并增添大纲

一、背景&#xff1a; 客户方提供过来一个开放平台的pdf文档&#xff0c;文档里有几十个接口&#xff0c;没有大纲和目录可以定位到具体内容&#xff0c;了解整体的API功能&#xff0c;观看体验极度差劲&#xff0c;所以想使用Python代码自动解析pdf文档&#xff0c;给文档增添…

【Spring实战】17 REST服务介绍

文章目录 1. 为什么出现2. 拥有哪些优势3. Spring中的应用4. spring-boot-starter-data-rest总结 REST&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;通常用于设计网络应用程序的服务接口。RESTful 服务是基于 REST 原则构建的网络服…

手机录屏没有声音?让你的录屏有声有色

“有人知道手机录屏怎么录声音吗&#xff1f;今天录制了一个小时的直播视频&#xff0c;后面查看的时候发现没有声音&#xff0c;真的非常崩溃&#xff0c;想问问大家有没有办法&#xff0c;解决这个问题。” 在手机录屏的过程中&#xff0c;有时候我们可能会面临录制视频没有…

socket实现视频通话-WebRTC

最近喜欢研究视频流&#xff0c;所以思考了双向通信socket&#xff0c;接下来我们就一起来看看本地如何实现双向视频通讯的功能吧~ 客户端获取视频流 首先思考如何获取视频流呢&#xff1f; 其实跟录音的功能差不多&#xff0c;都是查询电脑上是否有媒体设备&#xff0c;如果…

杰发科技AC7840——Eclipse环境DMA注意事项

0.序 用 户 使 用 DMA 时 &#xff0c; 所 有 DMA 搬 运 的 SRAM 数 据 都 必 须 存 放 在 SRAM_U 区 (0x20000000~0x2000EFFF) 。 1. 修改办法 第一步&#xff1a; RAM定义 /* Specify the memory areas */ MEMORY {FLASH (rx) : ORIGIN 0x00000000, LENGT…

多功能号卡推广分销管理系统 流量卡推广分销网站源码

一套完善&#xff0c;多功能&#xff0c;的号卡分销系统&#xff0c;多接口&#xff0c;包括运营商接口&#xff0c;无限三级代理&#xff0c;最简单易用的PHP~ 目前市面上最优雅的号卡系统&#xff01;没有之一 软件架构说明 环境要求php7.3以上&#xff08;建议低于8.0&…

面试题理解深层次的数组名

目录 引言 一&#xff1a;一维数组 举例如下 1.铺垫知识 数组名是数组首元素的地址&#xff0c;但是有两个特殊情况 &#xff08;1&#xff09;sizeof(数组名) &#xff08;2&#xff09;&数组名 2.分析讲解上述代码结果 2.字符数组 举例一如下 1.知识铺垫 …

Python内置库os和sys的常用方法汇总

更多Python学习内容&#xff1a;ipengtao.com Python是一门强大的编程语言&#xff0c;具有丰富的标准库&#xff0c;其中包括os和sys两个常用模块。os模块用于与操作系统交互&#xff0c;提供了许多文件和目录操作的方法&#xff0c;而sys模块用于与Python解释器进行交互&…

OceanBase入选Gartner®云数据库管理系统魔力象限“荣誉提及”

近日&#xff0c;全球IT市场研究和咨询公司Gartner发布最新报告《Magic Quadrant™ for Cloud Database Management Systems》&#xff08;全球云数据库管理系统魔力象限&#xff09;。全自研分布式数据库 OceanBase 入选“荣誉提及”&#xff0c;2022 年推出的云数据库 OB Clo…

uniapp---安卓真机调试提示检测不到手机【解决办法】

最近在做APP&#xff0c;由于华为手机更新过系统&#xff0c;再次用来调试APP发现就不行了。下面给出具体的解决方法&#xff1a; 第一步&#xff1a;打开【允许开发人员选项】 找到【设置】点击【关于手机】找到【版本号】点击7次或多次&#xff0c;允许开发人员选项。 第二…

性能优化:Spark SQL中的谓词下推和列式存储

Apache Spark是一个强大的分布式计算框架&#xff0c;Spark SQL是其一个核心模块&#xff0c;用于处理结构化数据。性能优化是大数据处理中的一个关键问题&#xff0c;本文将深入探讨Spark SQL中的两个性能优化技术&#xff1a;谓词下推&#xff08;Predicate Pushdown&#xf…