类和对象【1】初识

news2024/11/28 2:52:50

全文目录

  • 引言(初识面向对象)
  • 类和对象
    • 定义
      • 类访问限定及封装
      • 类定义的两种方式
    • 类实例化与类对象大小
    • this指针
  • 总结

引言(初识面向对象)

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

比如洗衣服这个操作,对于面向过程的C语言而言,就是要根据洗衣服的过程按照逻辑逐步依次实现:
在这里插入图片描述
最多将放洗衣液的多个步骤封装一个函数,进行多遍的冲洗操作写一个循环。总之面向的是洗衣服的过程。

但对于面向对象的C++而言,洗衣服的过程就可以按照封装的几个对象之间的交互实现。比如分为人、衣服、洗衣液与洗衣机:
在这里插入图片描述
洗衣服只需要人将衣服与洗衣液放到洗衣机中,由洗衣机执行操作即可。有些洗衣机对象还可以实现自动加洗衣液,此时洗衣液就是洗衣机的一个内部对象。总之面向的是洗衣服时参与到的对象。

不难发现,面向对象的操作过程是要比面向过程的操作过程简单高效的。也就是说,面向对象编程是一种相对高级的编程方式。

类和对象

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

struct Stack
{
	int* _data;
	int _top;
	int _capacity;

	void init();	
	void push();
	void pop();
	void destory();
};

在C语言中实现的栈,结构体中只有变量,是通过函数来操作结构体中的变量;而C++的栈结构体中可以定义函数,这其实就是一个类。struct可以用来定义类,在C++中有一个专门的关键字class来定义类:

定义

class定义类的格式如下:

class Classname
{
	//类的主体(成员变量与成员函数)
};

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

类访问限定及封装

用类将对象的属性与方法结合到一起就是封装,并且通过访问限定隐藏属性以及方法的细节,只向用户提供接口,使用户更方便的使用类:

有三种访问限定符:public(公有)、protected(保护)、private(私有):

class Classname
{
public:
	//公共权限:类内可以访问,类外可以访问;
protected:
	//保护权限:类内可以访问,类外不可以访问(子类可以访问);
private:
	//私有权限:类内可以访问,类外不可以访问(子类不可以访问);
};

不难发现,由于类需要向用户提供接口,而隐藏属性,所以类的成员函数一般都是放在公有域,成员变量都放在私有域。

需要注意的是:

  1. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止, 如果后面没有访问限定符,作用域就到 } ,即类结束
  2. class的默认访问权限为private,struct为public(因为struct要兼容C)。

类定义的两种方式

定义类时,可以有两种方式:函数的声明与定义在一起放在类中或者函数的声明与定义分离,声明放在类中,函数定义放在.cpp文件中:

需要注意的是,如果在类中定义成员函数,这个函数会被默认当成内联函数(这里简单写一个日期类例举):

class Date
{
public:

	void InitDate(int year = 2023, int month = 2, int day = 10)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date& AddDate(int day)
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	int GetMonthDay(int year, int month)
	{
		int monthdays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			monthdays[month] = 29;
		}
		return monthdays[month];
	}
private:
	int _year;
	int _month;
	int _day;
};

如果声明和定义分离,在定义函数时需要类名::函数名的方式定义:

class Date
{
public:
    void InitDate(int year = 2023, int month = 2, int day = 10);
	Date& AddDate(int day);
	int GetMonthDay(int year, int month);
private:
	int _year;
	int _month;
	int _day;
};

void Date::InitDate(int year = 2023, int month = 2, int day = 10)
{
	_year = year;
	_month = month;
	_day = day;
}
Date& Date::AddDate(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}
int Date::GetMonthDay(int year, int month)
{
	int monthdays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		monthdays[month] = 29;
	}
	return monthdays[month];
}

在定义类时,建议使用第二种方式,并且将公有的成员函数定义在私有的成员变量之前

类实例化与类对象大小

在上面定义的类只是一种类类型,相当于房子的图纸,并不在内存中开辟空间。
用类创建对象的过程称为类的实例化,实例化的对象占有具体的内存空间。
类名就是类类型的类型名,一个类类型可以实例化多个类对象,比如上面的日期类:

int main()
{
    //实例化三个类对象
	Date d1;
	Date d2;
	Date d3;
	//对三个类对象调用其成员函数进行初始化
	d1.InitDate();
	d2.InitDate(2023, 5, 14);
	d3.InitDate(2000, 1, 1);
	return 0;
}

上面的内容并不难理解,但是由于成员函数也是包含在类对象中的,类的大小应该如何计算?
在C语言部分,我们了解了如何计算结构体的大小,结构体在内存分配时遵循内存对齐的规则:
戳我看结构体内存对齐详解哦

类的大小也遵循内存对齐的规则,但是对于成员函数,它虽然封装在类中,但是却不占用类对象的空间。成员函数的只保存一份在代码段,类对象中只保存成员变量

int main()
{
	Date d1;
	cout << sizeof(d1) << endl;
	return 0;
}

在这里插入图片描述
所以对于上述Date类对象d1的大小只包括三个int型的成员变量,根据内存对齐,大小就是12字节。

对于空类,会有一个字节的空间以区分。

this指针

在上面提到过,私有的成员变量在类内部是可以访问的。比如我们对不同的类进行加天数的操作后的结果是不同的:

int main()
{
	//类实例化
	Date d1;
	Date d2;
	//类初始化
	d1.InitDate();
	d2.InitDate(2023, 5, 14);
	//不同的日期类对象+100天
	d1.AddDate(100);
	d2.AddDate(100);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
那么成员函数是怎么知道是哪个对象调用的,并且获取到该类的成员变量并对其进行操作的?

这是由于,我们在调用成员函数时,其实是在替某个对象调用其成员函数。类对象的成员函数参数列表中其实有一个隐含的this指针,它在参数列表的左边
this指针就是调用成员函数的对象的指针,它的作用就是帮助成员函数调用成员变量。其实上面的AddDate函数本质上是这样的:

//Date& Date::AddDate(Date *const this, int day); //错误代码:this指针必须隐式传参

在函数内部是这样实现访问成员变量的:

{
	this->_day += day;
	while (this->_day > GetMonthDay(this->_year, this->_month))
	{
		this->_day -= GetMonthDay(this->_year, this->_month);
		++(this->_month);
		if (this->_month > 12)
		{
			++(this->_year);
			this->_month = 1;
		}
	}
	return *this;
}

虽然显式的用this指针访问成员变量是可以的,但是这样的代码很不好看,不简洁。

this指针的特性:

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

总结

在这篇文章中,初步了解了类和对象,包括定义、实例化以及this指针。接下来会继续深入介绍类和对象的相关知识,希望大家持续关注哦

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦

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

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

相关文章

如何使用Understand软件查看STM32单片机HAL库函数调用关系

在使用STM32单片机的HAL库函数编程时&#xff0c;会发现好多中断函数里面都有各种回调函数&#xff0c;还有好多函数的调用深度比较深&#xff0c;在编写代码的时候&#xff0c;有时候想查看某个函数是如何被调用的&#xff0c;查看起来非常麻烦。这时候就可以使用Understand软…

Android活动生命周期

GitHub&#xff1a;https://github.com/MADMAX110/Stopwatch 活动的生命不只是有创建和撤销&#xff0c;onCreate和onDestroy方法用来处理整个生命周期&#xff0c;除了这两个方法&#xff0c;另外还有一些处理活动可见性的生命周期方法。 具体来讲&#xff0c;有三个关键的生…

Flink学习——DataStream API

一个flink程序&#xff0c;其实就是对DataStream的各种转换。具体可以分成以下几个部分&#xff1a; 获取执行环境&#xff08;Execution Environment&#xff09;读取数据源&#xff08;Source&#xff09;定义基于数据的转换操作&#xff08;Transformations&#xff09;定义…

.net6 接收json数据 Controller http post

.net6 接收json数据 Controller http post 要添加这两个包 前端ajax请求 function tst() {$.ajax({type: "POST",contentType: "application/json",url: "/HelloWorld/Welcome",data: JSON.stringify({ "ID":1,"name": &…

Qt实现undo和redo功能--连续后退

刚开始想做这个的时候&#xff0c;我专门去找了Qt官方的测试例子&#xff0c;运行起来点了点&#xff0c;代码翻了翻。然后照猫画虎般的写了个测试例子。 不明白&#xff0c;为什么每个例子旁边会有个命令的显示列表&#xff0c;还巨丑的那种&#xff0c;这如果要放在别的程序…

DJ6-4 文件存储空间的管理

目录 6.4.1 空闲表 1、存储空间的分配与回收 2、空闲表法的优缺点 6.4.2 空闲链表 1、空闲盘块链 2、空闲盘区链 6.4.3 位示图 1、位示图的表示 2、存储空间的分配 3、存储空间的回收 4、位示图法的优缺点 6.4.4 成组链接 1、空闲盘块的组织 plus 个人理解图…

前端web入门-HTML-day01

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 HTML初体验 HTML 定义 标签语法 总结&#xff1a; HTML 基本骨架 基础知识&#xff1a; 总结&#…

20年磨一剑,数慧时空推出智能遥感云平台DIEY及自然资源多模态大模型“长城”

5月17日&#xff0c;主题为“时空智能 从感知到决策”的第十二届全球地理信息开发者大会&#xff08;WGDC2023&#xff09;在北京昆泰酒店举行。大会聚集了千余位产业专家、行业用户、创新企业等业界精英&#xff0c;共话时空智能时代下的技术发展与应用创新。中国科学院院士、…

初始计算机操作系统——进程与线程,多线程以及Thread类的创建和属性

目录 通过前半篇文章需要了解 1.进程&#xff08;process/task&#xff09;&#xff1a;运行起来的可执行文件。 为啥要有进程&#xff1f; 如何解决这个问题&#xff1f; &#xff08;1&#xff09;进程池&#xff1a; &#xff08;2&#xff09;使用线程&#xff1a; 为啥线…

国考省考行测:判断推理,类比推理1,概念关系,包含关系,交叉关系,并列关系,全同关系

国考省考行测&#xff1a;判断推理&#xff0c;类比推理1&#xff0c;概念关系&#xff0c;包含关系&#xff0c;交叉关系&#xff0c;并列关系&#xff0c;全同关系 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#x…

chatgpt赋能Python-libreoffice_python扩展

LibreOffice Python扩展: 提升办公效率的利器 如果你一直在寻找一种提高办公效率的方法&#xff0c;那么你肯定会喜欢LibreOffice Python扩展。作为LibreOffice的一个特性&#xff0c;它可以让你使用Python编写宏程序自动化你的日常办公任务。 什么是LibreOffice Python扩展&…

力扣sql中等篇练习(二十一)

力扣sql中等篇练习(二十一) 1 最大数量高于平均水平的订单 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # Write your MySQL query statement below WITH t1 as (SELECT order_id,avg(quantity) AquantityFROM OrdersDeta…

chatgpt赋能Python-numpy数据预处理

Numpy数据预处理综述 介绍 Numpy是Python中最流行的数学库之一&#xff0c;可以用于高效的处理大型数据。Numpy提供了各种强大的数据结构和函数&#xff0c;使得数据分析和处理变得更加容易和直观。本文将介绍numpy中的一些数据预处理技术&#xff0c;包括数据清洗、缩放、归…

chatgpt赋能Python-mingw编译python

Mingw编译Python&#xff1a;一种常用的解决方案 在Python开发中&#xff0c;为了获得更好的性能&#xff0c;我们通常会选择编译Python源代码。而在Windows平台上&#xff0c; Mingw编译器是一种常用的解决方案。本文将介绍Mingw编译Python的过程&#xff0c;并探讨其优缺点。…

chatgpt赋能Python-numpy创建

Numpy&#xff1a;Python中的数学计算利器 作为Python中进行数学计算和科学计算最重要的库之一&#xff0c;Numpy已经成为了Python编程中的标配。Numpy以其出色的数组处理能力和矩阵运算效果&#xff0c;让Python用户的数学计算和科学计算变得更加简单高效。在本篇文章中&…

【半监督学习】Match系列.4

介绍几篇关于半监督学习的论文&#xff1a;CLS&#xff08;arXiv2022&#xff09;&#xff0c;Ada-CM&#xff08;CVPR2022&#xff09;&#xff0c;SemiMatch&#xff08;CVPR2022&#xff09;. CLS: Cross Labeling Supervision for Semi-Supervised Learning, arXiv2022 解…

mysql增量备份

目录 一、修改配置文件&#xff0c;开启增量备份功能 &#xff08;1&#xff09;查看是否已经开启了 &#xff08;2&#xff09;修改配置文件开启 &#xff08;3&#xff09;增量记录文件 二、还原增量备份 &#xff08;1&#xff09;修改了数据 &#xff08;2&#xff…

使用thrift进行RPC通信(附c程序示例)

前言 为了实现不同语言的程序跨进程、跨主机通信&#xff0c;一般可以采用mq或rpc框架来实现。 对于异步通知的场景可以使用mq&#xff0c;如zeroMQ。 但对于某些实时性较强且同步的应用场景&#xff0c;使用成熟的rpc框架来实现也是一种比较更好的选择。 开源的rpc框架有很…

MySQL---游标,异常处理,循环构建表

1. 游标 游标(cursor)是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用光标对结果集进行 循环的处理。光标的使用包括光标的声明、OPEN、FETCH 和 CLOSE. -- 声明语法 declare cursor_name cursor for select_statement -- 打开语法 open cursor_name -- 取值语…

由浅入深Netty基础知识NIO三大组件原理实战

目录 1 三大组件1.1 Channel & Buffer1.2 Selector1.3 多线程版设计1.4 多线程版缺点1.5 线程池版设计1.6 线程池版缺点1.7 selector 版设计 2 ByteBuffer2.1 ByteBuffer 正确使用姿势2.2 ByteBuffer 结构2.3 调试工具类2.4 ByteBuffer 常见方法2.4.1 分配空间2.4.2 向 buf…