C++初阶--类与对象(1)

news2024/12/23 18:18:58

文章目录

  • 类的引入
  • 类的定义
  • 访问限定符
  • 类成员的注意事项
    • 变量名的冲突
  • 类的实例化
  • 类成员的声明与定义
  • 类的大小
  • this指针
    • 特性
  • 总结

类的引入

在c语言中,我们会这样写一个栈:

struct Stack
{
	int* a;
	int top;
	int capacity;
};

void StackInit(struct Stack* ps);
void StackPush(struct Stack* ps, int x);

先写出一个栈的结构体出来,然后写出有关栈的函数出来;我们会把对于栈的操作部分拆分出来,所以我们说C语言是面向过程的

而在C++中,对于结构体来说,还可以把函数也写进结构体中
并且对于结构体变量类型,可以省略struct

#include<stdlib.h>
struct Stack
{
	int* a;
	int top;
	int capacity;

	void Init()
	{
		a = (int*)malloc(sizeof(int)*4);
		top = 0;
		capacity = 4;
	}
	void Push(int x)
	{
		//空则扩容
		if (top == capacity)
		{
			int newcapacity =  capacity * 2;

			int* New = (int*)realloc(a, sizeof(int) * (newcapacity));
			if (New == nullptr)
			{
				perror("Newsapce Fail");
				exit(-1);
			}
			a = New;
			capacity = newcapacity;
		}
		//插入
		a[top] = x;
		top++;
	}
};

int main()
{
	Stack s1;
	s1.Init();
	s1.Push(5);
	
}

上面的这种struct的定义,C++更喜欢使用class来代替

类的定义

class Student
{

};

class是定义一个类的关键字,Student是类的名字,括号内是类的主体;大体与struct是相似的;
在主体部分,类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数

class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	void Init()
	{
		a = nullptr;
		top = 0;
		capacity = 4;
	}
	void Push(int x)
	{
		//空则扩容
		//...
		//插入
		a[top] = x;
		top++;
	}
};

private和public是访问限定符

对于类定义的写法,一般有两种,第一种的像上面的一样,将成员函数的内容直接在类中写出,另一种就是将成员函数声明放在类中,函数的定义写在另一个文件中。
在这里插入图片描述

注意:第一种方法中,将函数直接在类中定义,会把函数的内容直接在类中展开,也就是说,直接在类中定义的话相当于是一个内联函数,所以如果函数内容较长时,还是建议写第二种方法;

访问限定符

在这里插入图片描述
C++通过访问限定符,用来控制不同代码块之间的访问权限,它们决定了类中的成员是否可以被访问和使用。

public:被public修饰的成员可以被任意代码块进行访问。

protected:被protected修饰的成员可以被当前类、同一包类、以及之类进行访问。
private:被pricate修饰的成员只能被当前类内部的其他成员所访问。

访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止

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

这也就可以解释class和struct的区别:
C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private
所以我们会在class类中写清楚private和pubilc。

类成员的注意事项

变量名的冲突

class Date
{
private:
	//声明
	int _year;
	int _month;
	int _day;
public:
	void Init(int year, int month, int day)
	{
		/*year = year;
		month = month;
		day = day;*/
		//错误的,变量名冲突

		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
};

在定义成员变量名的时候,需要注意成员变量名是否冲突,因为它们都在一个作用域中,所以在这里建议对于成员变量名最好多加一个符号来表示这是成员变量的,用来区分变量名。

类的实例化

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

int main()
{
	Date d1;
	Date d2;
	//....
}

上面的d1,d2我们称之为类的对象。
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

类成员的声明与定义

struct Stack
{
	int* a;
	int top;
	int capacity;
};
int main()
{
	Stack s1;
	s1.capacity = 10;
	//正确的
	Date d1;
	d1._year=10;
	//错误的
}

在上面的限定符已经讲过,Date的成员变量都是private中的,无法在作用域外进行访问。而Stack是struct定义的,所以允许我们进行访问。但这里要注意的是Date中的成员变量,实际上只是声明而已,实际上的定义是在创建对象时定义的。

我们可以这样试验:
在这里插入图片描述
在public限定符中写一个成员变量,
在这里插入图片描述
它是可以在作用域外被使用的,因为它是公有的;

而我们定义多个对象时,
在这里插入图片描述
它们也可以打印出对应的内容。
这就说明了对于类的成员变量来说,在类中都只是声明而已,无论在private还是public,那只是限定符而已。定义都必须要在对象中进行,这样在多个对象中进行访问才不会产生冲突

而对于成员函数来说,无论你是在类中定义,还是类外定义,你都会有一个函数地址,存在多个对象时,只需要调取你的地址,在栈区中建立栈帧即可。

所以我们可以总结:类的成员变量的定义均在对象中,而类的成员函数,不用在对象中进行定义

在这里插入图片描述

类的大小

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

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
};
class SizeNuLL
{

};
class Size1NULL
{
	class Size2NULL
	{

	};
};
int main()
{
	cout << sizeof(d1) << endl;//12
	SizeNuLL s1;
	cout << sizeof(s1) << endl;//1
	Size1NULL s2;
	cout << sizeof(s2) << endl;//1
	无成员变量的类,对象大小开一个字节,这个字节不存储有效位
	用来标识的对象存在过
}

这里的计算只计算成员变量,计算方式与结构体的计算方式是一样的,会利用到内存对齐的规则。
而对于无成员变量的类来说,对象大小开一个字节,这个字节不存储有效位,用来标识的对象存在过。

this指针

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

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
};
int main()
{
	Date d1;
	d1.Init(2023, 10, 19);
	d1.Print();
	Date d2;
	d2.Init(2022, 9, 8);
	d2.Print();
}

在这里插入图片描述
上述代码中:成员函数的参数中我们没有引用相关对象的参数,对于不同对象中,它是怎么识别的呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成。
在这里插入图片描述

当指针为空时:

Date* d3 = nullptr;
	//错误的,对象指针为空,this指针也为空
	d3->Init(2023, 10, 20);
	d3->Print();
	Date* d4;
	//错误的,d4没有初始化,指针相当于指向空
	d4->Init(2023, 10, 21);
	d4->Print();

特性

  1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
    在这里插入图片描述

  2. 只能在“成员函数”的内部使用

在这里插入图片描述3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
5. this指针存储的是当前被调用的成员函数对应的对象的地址,也就是在栈帧中。(一些编辑器会存储在寄存器中,如VS2022)

总结

类的成员变量实际上只是声明,定义会在变量中定义(当创建了一个类对象时);成员函数不在类对象里面,它属于公共部分,也就是每个类对象都可以调用它; 指针没有初始化和指向空,实质上都是没有指向一个存在的类对象,这样就导致指针不明确;在成员函数里面会有一个隐藏的this指针,用来表示指向成员变量,我们在编写代码不能显示this该步骤已经由编译器自动写好了,在成员函数中就可以直接调用变量;这也就说明指针为空的情况下,this指针找不到已有的成员变量;

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

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

相关文章

利用Bootstrap的分页组件实现分页效果

在网页开发过程中&#xff0c;如果碰到内容过多的情况&#xff0c;一般都会使用分页处理。 在<ul>元素上添加pagination类&#xff0c;在<li>元素上添加page-item类&#xff0c;在超链接中添加 page-link类&#xff0c;即可实现一个简单的分页。 目录 00-基础知识…

STM32项目工程的搭建

视频连接&#xff1a; [2-1]--入门 新建工程 及 工程搭建 -------------_哔哩哔哩_bilibili 1.STM32开发方式 1.标志库 表示直接调用已经写好的程序&#xff0c;通过类似于函数调用直接使用即可。 2.HAL库 程序员自己手动的操作寄存器进行编程 2.工程模板 3.搭建工程的步骤 1…

微信小程序OA会议系统数据交互

前言 经过我们所写的上一文章&#xff1a;微信小程序会议OA系统其他页面-CSDN博客 在我们的是基础面板上面&#xff0c;可以看到出来我们的数据是死数据&#xff0c;今天我们就完善我们的是数据 后台 在我们去完成项目之前我们要把我们的项目后台准备好资源我放在我资源中&…

Memcached和Memcache安装(64位win10)

Memcached和Memcache安装&#xff08;64位win10&#xff09; 一、Memcached和Memcache的区别&#xff1a;   网上关于Memcached和Memcache的区别的理解众说纷纭&#xff0c;我个人的理解是&#xff1a;   Memcached是一个内存缓存系统&#xff0c;而Memcache是php的一个扩展…

虚假KeePass网站利用Google Ads和Punycode推送恶意软件

导语 近日&#xff0c;一起利用Google Ads和Punycode进行恶意软件传播的事件引起了广泛关注。该事件利用虚假KeePass下载网站&#xff0c;通过Punycode编码伪装成KeePass密码管理器的官方域名&#xff0c;并在Google Ads广告中推广&#xff0c;诱导用户下载恶意软件。这种新型的…

C++初阶(四)类和对象

文章目录 一、面向过程和面向对象初步认识二、类的引入三、类的定义1、类的概述2、类的两种定义3、成员变量命名规则的建议 四、类的访问限定符及封装1、访问限定符2、封装 五、类的作用域六、类的实例化七、类对象模型1、如何计算类对象的大小2、 类对象的存储方式猜测3、 验证…

【rust/树莓派】使用rppalembedded-graphics控制st7789 LCD屏幕

说在前面 树莓派版本&#xff1a;4bLCD模块&#xff1a;ST7789V2 240*280 LCD树莓派系统&#xff1a;Linux raspberrypi 5.15.76-v8 #1597 SMP aarch64 GNU/Linuxrust版本&#xff1a;rustc 1.73.0 模块详情 某雪的1.69inch LCD模块&#xff0c;包含杜邦线 准备工作 树莓派…

JavaSE编程题目练习(一)

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;欢迎关注小弟&#xff01; 博主小留言&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟Cool&#xff0…

Rust 中的String与所有权机制

文章目录 一、string二、所有权2.1 所有权与作用域2.2 对所有权的操作2.2.1 转移2.2.3 拷贝2.2.3 传递 2.3 引用2.3.1 借用2.3.2 可变引用 一、string 之前学习过 Rust 只有几种基础的数据类型&#xff0c;但是没有常用的字符串也就是String&#xff0c;今天来学习一下 String…

Opensuse Tumbleweed快速部署K8S-1.28.2

** #查看你的网卡信息 nmcli device show#设置你的静态IP nmcli connection modify ens32 ipv4.method manual \ipv4.addresses 172.16.20.214/24 ipv4.gateway 172.16.20.1 \ipv4.dns 114.114.114.114#重启网卡生效 nmcli c down ens32 && nmcli c up ens32#添加DNS …

Java IDEA java.lang.IllegalStateException: Failed to introspect Class报错原因和解决办法

Java IDEA java.lang.IllegalStateException: Failed to introspect Class报错原因和解决办法 1. 报错如下&#xff1a;2. 解决 在maven右侧查看Dependencies冲突参考 1. 报错如下&#xff1a; 发现是因为 org.redisson:redisson.spring.boot.starter 3.10.6这个包引入不进来导…

如何使用 Canvas和HTML5中的SVG画一个矩形?

使用Canvas和SVG分别绘制矩形的方法如下&#xff1a; Canvas绘制矩形&#xff1a; <canvas id"canvas" width"200" height"200"></canvas><script>const canvas document.getElementById(canvas);const ctx canvas.getCon…

python随手小练6

1、汉诺塔 汉诺塔&#xff1a;汉诺塔&#xff08;又称河内塔&#xff09;问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放…

燃气管网智能巡检系统

燃气管网维护工作繁杂&#xff0c;涉及人员、资源、巡检等&#xff0c;稍一疏忽就会使我们的工作陷入被动&#xff0c;可见启用燃气管网智能巡检系统是很有必要的。 燃气管网智能巡检系统综合管理智能平台&#xff0c;可对燃气管网数据的统一管理&#xff0c;实现对日常巡查、养…

【Arduino TFT】基于 ESP32S3 S7789 240x240 TFT实现的龙猫太空人天气时钟

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-10-21 ❤️❤️ 本篇更新记录 2023-10-21 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

「2021年TYWZ普及模拟题」多边形 待定题解

文章目录 题目描述输入格式输出格式样例样例输入 1样例输出 1样例输入 2样例输出 2 数据范围与提示前置知识思路与部分实现完整代码文章小结 题目描述 一个凸多边形具有非常多优秀的性质&#xff0c;它的任意内角小于或等于 18 0 。 180^。 180。 。 小 F 将 n n n 条边交给…

Linux内存管理(1):memblock

一、memblock分配器初始化 在内核初始化过程中也需要分配内存,使用的页帧分配器叫memblock(早期的内核版本使用BootMem,新版本内核已不再用)。 memblock是系统启动过程中的一个中间阶段的内存管理, 负责在系统上电到内核内存管理模型初始化之前这段时间的物理内存分配、预留…

微信小程序之授权登录以及授权登录流程讲解

前言&#xff1a; 之前博主给大家介绍了小程序的授权登录案例&#xff0c;今天我使用结合项目&#xff0c;后台的方式来给大家展示 一&#xff0c;微信授权登录流程 步骤流程&#xff1a; 1.小程序调用wx.login() 获取 临时登录凭证code &#xff0c;并回传到开发者服务器 2.开…

解决CondaHTTPError HTTP 000 CONNECTION FAILED for url解决方法

解决CondaHTTPError: HTTP 000 CONNECTION FAILED for url解决方法 问题&#xff1a;使用conda install命令安装包提示CondaHTTPError: HTTP 000 CONNECTION FAILED for url 分析&#xff1a;网络连接问题&#xff0c;大概率是网速不行或者源没有换 解决方案&#xff1a;修改国…

华为eNSP配置专题-OSPF路由协议的配置

文章目录 华为eNSP配置专题-OSPF路由协议的配置0、概要介绍1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、终端构成和连接2.2、终端的基本配置 3、OSPF路由的配置3.1、OSPF路由的配置3.1.1、在R1上配置OSPF3.1.2、在R2和R3上配置OSPF3.1.3、查看和监控OSPF 华为e…