C++类与对象 (上)

目录

前言:

类和对象的理解

类的引入

类的定义与使用方式

访问限定符

类的两种定义方式

成员变量的命名规则

类的作用域

类的实例化

类对象模型

计算类对象的大小

类对象的存储方式

this指针


前言:

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

类和对象的理解

是一个抽象的概念,描述了一类对象的共同属性行为

对象是类的具体化,它是类的实例,具有类中定义的属性和行为;

在C++中,通常由数据成员成员函数组成,数据成员是类的属性,它们描述了对象的状态,成员函数是类的行为,它们描述了对象可以执行的操作,对象的创建是通过类的实例化来完成的,当程序需要使用类时,可以通过创建类的对象来使用类的属性和行为;

举例如下:

将“汽车”看作一个类,在这个类中定义了汽车的属性和行为,比如颜色、品牌、速度等属性,以及加速、刹车、转弯等行为;当我们要描述具体一辆汽车时,就需要创建一个该类的对象,并根据需要设置其相应的属性值或对其进行行为操作;

类的引入

由于C++兼容C语言中struct的所有用法,同时C++对关键字struct进行了升级,将struct升级为类;

  •  struct    类名 (类名即为变量类型)
//c语言
struct Stack
{
	int* a;
	int top;
	int capacity;
};
int main()
{
	//Stack s1; //C语言 ---> 未定义的标识符
	struct Stack s1;//只能采取带上struct关键字定义变量
	return 0;
}
//c++ 
struct Stack
{
	int* a;
	int top;
	int capacity;
};
int main()
{
	Stack s1;//可直接采取这种方案定义变量,不需要加上struct的关键字
	return 0;
}
//c语言定义链表结点
struct ListNode
{
  //ListNode* next;//C语言 ---> 未定义的标识符
  struct ListNode* next;
	int val;
};
//c++定义链表结点
struct ListNode
{
    ListNode* next;//编译通过
	int val;
};
  • C++结构体中可以定义函数;
//c++ 类里面可以定义函数
struct Stack
{
	int* a;
	int top;
	int capacity;
	//初始化栈
	void Init()
	{
		a = 0;
		top = 0;
		capacity = 0;
	}
};

 C++用关键字 class 代替 struct;

类的定义与使用方式

class 类名
{

   //类体: 由成员变量与成员函数组成

}; //此处分号不可省略

类的成员:类中的变量称为类的属性或成员变量类中的函数称为类的方法或成员函数

访问限定符

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

 访问限定符说明:

  1. public修饰的成员类外可以直接被访问
  2. protected和private修饰的成员类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止;
  4. 如果后面没有访问限定符,作用域就到 } 即类结束;
  5. class的默认访问权限为privatestruct默认访问权限为public(因为struct要兼容C)
class Stack
{
private:
	int* a;
	int top;//a,top,capacity--->成员变量私有
	int capacity;
    //private的作用域从private开始到public,若没有public,直接到类结束;
    //由于class的默认访问权限为私有,省略掉private,三个成员变量依旧私有
public:
	//初始化栈
	void Init()// Init()函数公有
	{
		a = 0;  
		top = 0;
		capacity = 0;
	}
}; //类结束

类定义的惯例:成员变量私有,成员函数公有;

class Stack
{
public:
	int* a;
	int top;
	int capacity;
	//初始化栈
	void Init()
	{
		a = 0;  
		top = -1;
		capacity = 0;
	}
	//空栈的判断
	bool StackEmpty()
	{
		return (top == -1);
	}
}; 
int main()
{
	Stack s1;
	s1.Init();
	//判断方式1:空栈, 若top=0,表示指向栈顶元素的下一个位置;
	//         空栈, 若top=-1,表示指向栈顶元素的位置;
	//栈的定义方式不同,如下判断方法可能导致出错;
	if (s1.top==0)
    
   //判断方式2:采取访问成员函数进行判断,直接调用判空函数,不会出错
	if (!s1.StackEmpty())
	{

	}
	//如上就是成员变量私有,成员函数公有的原因
	return 0;
}

类的两种定义方式

定义方式1:类的声明放在.h文件中,成员函数定义放在.cpp文件中;

                    (注:成员函数名前加 类名 ::)

定义方式2:声明和定义全部放在类体中;

                  (注:成员函数如果在类中定义编译器可能会将成员函数当成内联函数处理)

成员变量的命名规则

class Date
{
public:
	void Init(int year,int month,int day)
	{
		// 这里的year到底是成员变量,还是函数形参?
		year = year;
		//局部优先,year为函数形参
		//局部优先是指在函数内部创建了一个和全局变量同名的局部变量时;
		//函数内部对该变量的操作会优先作用于局部变量,而不会改变全局变量的值
	}
private:
	int year;
	int month;
	int day;
};

为了避免如上情形,C++采用成员变量前加 _

class Date
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
	}
private:
	int _year;
	int _month;
	int _day;
	//year month day成员变量前加 _
};

类的作用域

定义了一个 新的作用域类的所有成员都在类的作用域中
类体外定义成员时,需要使用 ::作用域限定符指明成员属于哪个 类域
c++中由{ }所定义的皆为作用域;
class Stack
{
  //变量的声明,没有在内存中开辟空间
	int* a;
	int top;
	int capacity;
public:
	void Init();
	bool StackEmpty();
};
//需要指定Init()函数属于Stack类域
void Stack::Init()
{
	a = 0;
	top = 0;
	capacity = 0;
}

类的实例化

用类的类型创建对象的过程,称为类的实例化;
  1. 类是对对象进行描述的是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;
  2. 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
class Date
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
	}
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date::_year = 2023;//编译错误,成员变量为声明,没有开辟内存空间存储;
   // Date d; d.year=2023  //正确做法
	return 0;
}
//Date类是没有空间的,只有Date类实例化出的对象才有具体的年份

3. 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间

类对象模型

类对象模型:类对象模型是指将类的成员函数和成员变量存储在一起的方式,这种方式将类的成员函数和成员变量封装在一个对象中,通过该对象来访问类的成员;

计算类对象的大小

# include <iostream>
using namespace std;
class Date
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
	}
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	cout << sizeof(d) << endl;
	return 0;
}
问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?

类对象的存储方式

类对象的存储方式:

对象中只保存成员变量,成员函数存放在公共代码段,这种方式将类的成员变量存储在对象中,而将成员函数存放在公共代码段中,通过对象来访问类的成员函数;

结论:一个类的对象大小,实际就是该类中”成员变量”之和,注意考虑内存对齐 ;

空类的大小:空类的大小为1字节;即使一个类没有任何成员变量和成员函数,它也会占用1字节的内存空间;

空的结构体大小:空的结构体大小为0字节,与空类不同,空的结构体不占用任何内存空间;

//类中仅有成员函数--->1byte
//对象中无成员函数
class B
{
public:
	void f2() {}
};
int main()
{
	B b;
	cout << sizeof(b) << endl;
	return 0;
}
//空类的大小 ---> 1byte
//无成员变量的类开辟1个字节,该字节不存储有效数据
//标识定义的对象存在过
class C
{

};
int main()
{
	C c;
	cout << sizeof(c) << endl;
	return 0;
}

this指针

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;//年
	int _month;//月
	int _day;//日
};
int main()
{
	Date d1, d2;
	d1.Init(2023, 12, 17);
	d2.Init(2023, 12, 16);
	d1.Print();
	d2.Print();
	return 0;
}

运行结果:

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

this指针的特性:

  1. this指针的类型类型* const 由于const修饰this,this指针不允许被修改;
  2. 只能在“成员函数”的内部使用 (不能显示的写实参和形参,但是可以在类中显示的使用);
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针
  4.  this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

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

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

相关文章

我想开发一款跨平台桌面软件,请告诉我qt、electron、tauri、pyqt、flutter分别适合开发哪些跨平台桌面

不同的跨平台桌面开发工具适用于不同的应用场景和开发者需求。以下是关于 Qt、Electron、Tauri、PyQt、Flutter 的简要说明&#xff0c;以帮助你更好地选择适合你项目的工具&#xff1a; Qt: 适用场景&#xff1a; Qt 是一个强大的 C 框架&#xff0c;适用于开发需要高性能和原…

【LeetCode】数组精选17题——双指针、滑动窗口、前缀和

目录 快慢指针&#xff1a; 1. 移动零&#xff08;简单&#xff09; 2. 复写零&#xff08;简单&#xff09; 对撞指针&#xff1a; 1. 两数之和 II - 输入有序数组&#xff08;中等&#xff09; 2. 三数之和&#xff08;中等&#xff09; 3. 有效三角形的个数&#xff…

python语言中“缩进”说法,python中的缩进规则

本篇文章给大家谈谈python语言中“缩进”说法&#xff0c;以及python中的缩进规则&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 缩进是Python的灵魂 Python是一门独特的语言&#xff0c;它的代码块是通过缩进&#xff08;Indentation&#xff09;来标记的&…

QT自带打包问题:无法定位程序输入点?metaobject@qsound

文章目录 无法定位程序输入点?metaobjectqsound……检查系统环境变量的配置&#xff1a;打包无须安装qt的文件 无法定位程序输入点?metaobjectqsound…… 在执行release打包程序后&#xff0c;相应的release文件夹下的exe文件&#xff0c;无法打开 如有错误欢迎指出 检查系…

LCR 181. 字符串中的单词反转

解题思路&#xff1a; class Solution {public String reverseMessage(String message) {message message.trim(); // 删除首尾空格int j message.length() - 1, i j;StringBuilder res new StringBuilder();while (i > 0) {while (i >…

如何批量获取CSDN文章数据并进行持久化

自己去看文章数据的话&#xff0c;比较慢&#xff0c;所以一直想通过程序来批量获取CSDN的文章数据&#xff0c;最近研究了一下&#xff0c;发现还是挺简单的&#xff0c;能够直接通过解析json来获取文章数据&#xff0c;跟大家分享一下。 文章目录 一、步骤1、首先我们到自己的…

JavaScript数组分组groupBy

JavaScript 最近发布了一个方法 Object.groupBy&#xff0c;可以对可迭代对象中的元素进行分组。 语法&#xff1a; Object.groupBy(items, callbackFn)items 被分组的可迭代对象&#xff0c;如 Array。 callbackFn 对可迭代对象中的每个元素执行的函数。 举个例子&#…

结构型设计模式(一):门面模式 组合模式

门面模式 Facade 1、什么是门面模式 门面模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在为系统提供一个统一的接口&#xff0c;以便于访问子系统中的一群接口。它通过定义一个高层接口&#xff0c;简化了客户端与子系统之间的交互&#xf…

基于Java SSM框架实现图书店仓库进销存管理系统项目【项目源码+论文说明】

基于java的SSM框架实现图书店仓库进销存管理系统演示 摘要 仓库作为储存货物的核心功能之一&#xff0c;在整个仓储中具有非常重要的作用&#xff0c;是社会物质生产的必要条件。良好的仓库布局环境能够对货物进入下一个环节前的质量起保证作用&#xff0c;能够为货物进入市场…

FPGA设计与实战之时钟及时序简介1

文章目录 一、时钟定义二、基本时序三、总结一、时钟定义 我们目前设计的电路以同步时序电路为主,时钟做为电路工作的基准而显得非常重要。 简单的接口电路比如I2C、SPI等,复杂一点接口比如Ethernet的MII、GMII等接口,它们都有一个或多个时钟信号。 那么什么是时钟信号?它…

PADS9.5 : 原图绘图图纸尺寸下修改

原图绘图图纸尺寸下修改 图页边界线也要修改 如果二者选择不一致&#xff1a; 会出现下图所示情况&#xff1a;

Android hwcomposer服务启动流程

Android hwcomposer服务启动流程 客户端 binder远程调用 服务端 surfaceflinger --binder--> hwcomposer .hal文件编译时生成支持binder进程间远程调用通信的cpp文件 在out/soong/.intermediates/hardware/interfaces/graphics/composer/2.1/ 目录下找…

基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(三)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建3. 模型训练及保存1&#xff09;模型训练2&#xff09;模型保存 4. 模型生成1&#xff09;模型导入及调用2&#xff09;相关代码&#xff08;1&#xff09;布局文件&#xff08;2&#xff…

LCR 120. 寻找文件副本

解题思路&#xff1a; 利用增强for循环遍历documents&#xff0c;将遇见的id加入hmap中&#xff0c;如果id在hamp中存在&#xff0c;则直接返回id class Solution {public int findRepeatDocument(int[] documents) {Set<Integer> hmapnew HashSet<>();for(int d…

插入排序----希尔排序

希尔排序 希尔排序法又称缩小增量法。希尔排序法的基本思想是&#xff1a;先选定一个整数&#xff0c;把待排序文件中所有记录分成个gap组&#xff0c;所有距离为的记录分在同一组内&#xff0c;并对每一组内的记录进行排序。然后&#xff0c;取&#xff0c;重复上述分组和排序…

千亿露酒市场的未来之“露”

执笔 | 尼 奥 编辑 | 扬 灵 12月15日&#xff0c;以“以美为酿&#xff0c;品致未来”为主题的中国露酒产业发展大会暨露酒价值论坛在“中国酒都”宜宾举办。 近年来&#xff0c;露酒产业发展异军突起&#xff0c;市场销售规模超越黄酒、葡萄酒品类&#xff0c;成为中国酒…

【Qt QML 入门】TextEdit

TextEdit可以显示多行可编辑的格式化文。默认是无边框的&#xff0c;可以和父控件完美融合。 import QtQuick import QtQuick.Window import QtQuick.ControlsWindow {id: winwidth: 800height: 600visible: trueTextEdit {id: textEditanchors.centerIn: parenttext: "He…

Sentinel使用详解

组件简介 Sentinel是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景&#xff0c;例如秒杀、消息削峰填谷、集群流量控…