【C++】:类和对象(上)

目录

  • 一,面向过程和面向对象初步认识
  • 二,类的引入
  • 三,类的定义
    • 3.1 **类的说明**
    • 3.2 **类的访问限定符**
    • 3.3 **类的两种实现方式**
    • 3.4 **成员变量的命名规则 --- 加下划线**
  • 四,类的作用域
    • 4.1 **类域的说明**
    • 4.2 **类域与命名空间域的区分**
  • 五,类的实例化
  • 六,类的对象大小的计算
    • 6.1 **问题**
    • **6.2 类中成员函数的存储**
    • **6.3 类中什么都没有 --- 空类**
    • **6.4 类中仅有成员函数**
    • 6.5 结论
  • 七,类成员函数的this指针
    • **7.1 this 指针的引出**
    • **7.2 this指针的特性**

一,面向过程和面向对象初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

在这里插入图片描述
在这里插入图片描述

C++是 基于面向对象 (注意不是纯面向对象) 的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

在这里插入图片描述
在这里插入图片描述

二,类的引入

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

比如:之前在数据结构初阶中,
用C语言方式实现的栈,结构体中只能定义变量
现在以C++方式实现,会发现struct中也可以定义函数,并且struct名称就可以代表类型

#include <iostream>
using namespace std;

struct Stack
{
	//成员函数
	void Init(int n = 4)
	{
		arr = (int*)malloc(sizeof(int) * n);
		if (nullptr == arr)
		{
			perror("malloc申请空间失败");
			return;
		}

		capacity = n;
		top = 0;

	}

	//成员变量
	int* arr;
	int capacity;
	int top;
};

int main()
{
	//调用成员变量/函数时和结构体的用法一样
	struct Stack st1;
	st1.Init();

	Stack st2;
	st2.Init();

	return 0;
}

上面结构体的定义,在C++中更喜欢用class来代替

三,类的定义

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

3.1 类的说明

1.class 为定义类的关键字ClassName为类的名字{}中为类的主体,注意类定义结束时后面分号不能省略

2.类体中内容称为类的成员类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数

3.2 类的访问限定符

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

在这里插入图片描述

访问限定符说明:

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

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

【面试题】:

  • 问题:C++中struct和class的区别是什么?
  • 解答:C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序给大家介绍。

3.3 类的两种实现方式

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

class Stack
{
public://访问限定符:公有
	//成员函数
	void Init(int n = 4)
	{
		arr = (int*)malloc(sizeof(int) * n);
		if (nullptr == arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		capacity = n;
		top = 0;
	}

	void Push(int x)
	{
		//……扩容

		arr[top++] = x;
	}

	int Top()
	{
		assert(top > 0);
		return arr[top - 1];
	}

private://私有
	//成员变量
	int* arr;
	int capacity;
	int top;
};

2.类声明放在.h文件中,成员函数定义放在.cpp文件中。注意:成员函数名前需要加类名::

在这里插入图片描述
在这里插入图片描述

3.4 成员变量的命名规则 — 加下划线

在一些书中总是能看到一些局部变量会加下划线,这是为什么呢?其实这是为了区分成员变量。

如下图中的注释部分的代码,当成员变量与形参一模一样时,函数会调用失败。因为这样把自己赋给自己,会无法区分,所以赋值失败

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

		//这样把自己赋给自己,会无法区分,所以赋值失败
		/*day = day;
		month = month;
		year = year;*/
	}

private:

    //可以这样声明成员变量 
	int _day; // day_  m_day
	int _month;
	int _year;
};

int main()
{
	Data d;
	d.Init(2024, 4, 21);

	return 0;
}

当然,不是所有地方都是在变量前加下划线的,其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行

四,类的作用域

4.1 类域的说明

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

class Person
{
public:
 void PrintPersonInfo();
private:
 char _name[20];
 char _gender[3];
 int  _age;
};

// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
 cout << _name << " "<< _gender << " " << _age << endl;
 }

4.2 类域与命名空间域的区分

类的作用主要有两个:
(1) 定义成员,此时形成了一个类型,这个类型中有数据(变量)和方法(函数)
(2) 同时形成了一个类域,可以对里面的成员进行保护,也能防止命名冲突
命名空间域的作用:
是对全局的数据,方法进行名字隔离,防止命名冲突

五,类的实例化

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

5.1 类是对对象进行描述的。我们知道在定义一个类和声明变量时,内存是不会给它们开空间的。只有在用类实例化对象时,才是定义变量,此时才会开空间

在这里插入图片描述

5.2 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。

六,类的对象大小的计算

6.1 问题

类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?

#include "Stack.h"

int main()
{
	//类 -->图纸  实例化对象--> 用图纸造房子

	//用类实例化一个对象时,才是变量的定义。这时开了空间
	Stack st1;
	Stack st2;

	//实例化不同的对象调用成员函数的地址都是一样的。
	//成员函数存放在一块公共的区域(公共代码段)
	st1.Init();
	st2.Init();

	//都可以计算出类的大小
	cout << sizeof(st1) << endl;  //根据造出的房子测量
	cout << sizeof(Stack) << endl; //根据图纸上的尺寸

	return 0;
}

通过猜测,实测,验证我们得知:

类的对象的大小,实际就是对象中所有成员变量大小之和,当然它们也遵守内存对齐规则。

6.2 类中成员函数的存储

其实,实例化的对象中成员变量是不同的,但是调用的成员函数的地址都是一样的,如果每个对象内部都放一份,当一个类创建多个对象时,就会有很大的空间浪费。所以成员函数会存放在一块公共的区域(公共代码段)

6.3 类中什么都没有 — 空类

通过验证,空类的大小为1个字节。

class A
{};

6.4 类中仅有成员函数

通过验证,大小也为1个字节。

class A 
{
public:
   void f2() {}
};

6.5 结论

一个类的大小,实际就是该类中"成员变量"之和,当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节,这个字节不存储有效数据,只是为了标识对象被定义出来。

七,类成员函数的this指针

7.1 this 指针的引出

我们先来定义一个日期类 Date:

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

 }
 
private:
	 int _year;    
	 int _month;    
	 int _day;    
};

int main()
{
	 Date d1, d2;
	 
	 d1.Init(2024, 4, 20);
	 d2.Init(2024, 4, 21);
	 
	 d1.Print();
	 //d1.Print(&d1);

	 d2.Print();
	 //d2.Print(&d2);

	 
	 return 0;
}

对于上述类,有这样的一个问题:

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

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

如上图代码中注释的部分就是编译器的处理。

7.2 this指针的特性

  1. this指针的类型:类类型 const即成员函数中,不能给this指针赋值
  2. 只能在"成员函数"的内部使用
  3. this指针本质上是"成员函数"的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针
  4. this指针是"成员函数"第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
  5. this 指针一般情况下是作为形参存在栈中。但有些编译器是把它存放在寄存器 ecx 中,这样可以不压栈帧,是一种优化

在这里插入图片描述

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

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

相关文章

分析经过j2k压缩的dicom文件经验分享

最近碰到一个问题&#xff0c;在网上搜到是用JPEG 2000压缩的DICOM文件 JPEG 2000对应的transfer syntax UID为 1.2.840.10008.1.2.4.91 参考:https://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_8.7.3.html 该文件是用专业德国老牌开发库DCMTK生成的 (…

虚拟机VMware安装与Ubuntu

1.虚拟机安装 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;2fr6 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 2.Ubuntu下载 Download Ubuntu Desktop | Ubuntu 3.设置 如后续要下一些软件越大越好

Diffusion Model原理剖析

目录 前言1. DDPM演算法初览2. 图像生成模型共同目标3. VAE: Lower bound of l o g P ( x ) logP(x) logP(x)4. Diffusion Model背后的数学原理5. 为什么需要Sample?6. Diffusion Model的应用7. Diffusion Model成功的关键总结参考 前言 接着上篇文章 图像生成模型浅析&#…

15.C++常用的算法_拷贝和替换算法

文章目录 遍历算法1. copy()代码工程运行结果 2. replace()代码工程运行结果 3. replace_if()代码工程运行结果 4. swap()代码工程运行结果 遍历算法 1. copy() 代码工程 copy()函数不要因为使用而使用#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include&l…

dremio支持设置

Dremio 支持提供可用于诊断目的的设置。这些设置通过 Dremio UI&#xff1a;设置>支持启用&#xff08;或禁用&#xff09; 使用 Client Tools 可以配置当用户查看数据集中的数据时&#xff0c;Dremio 项目的工具栏上显示哪些客户端应用程序按钮。用户可以通过单击相应的工具…

免费ssl泛域名/泛解析证书获取教程

泛域名SSL证书&#xff0c;也称为通配符证书&#xff0c;它可以保护一个主域名下的所有子域名。这意味着&#xff0c;无论你有多少个子域名&#xff0c;只要安装了一个泛域名SSL证书&#xff0c;就可以实现全部子域名的安全保护。这种证书非常适合大型企业或有大量子域名的网站…

数电复习(五)半导体存储电路

半导体存储电路 5.1 概述5.2 SR锁存器5.3 触发器5.3.1电平触发的触发器5.3.2 边沿触发器5.3.3 脉冲触发(主从) 触发器5.3.4 触发器逻辑功能的转换 5.4 寄存器5.4.1 数码寄存器5.4.2 移位寄存器 5.5 存储器5.5.1 ROM5.5.2 随机存储器RAM5.5.3 存储器容量的扩展5.5.4 用存储器实现…

怎么申请免费SSL证书,如何安装

什么是SSL证书&#xff0c;SSL&#xff0c;即Secure Sockets Layer&#xff08;安全套接层&#xff09;&#xff0c;它是一种安全协议&#xff0c;用于在互联网通信中为数据提供加密保护&#xff0c;从而防止数据被窃听或篡改。而SSL证书则是由权威的数字证书认证机构&#xff…

数据结构面试常见问题:什么是哈希表?它的工作原理是什么?

哈希表的基本概念 在我们的日常生活中&#xff0c;我们经常需要存储和查找各种信息&#xff0c;这些信息可能是电话号码&#xff0c;地址&#xff0c;或者是商品的价格等等。这些信息的存储和查找&#xff0c;就像是我们在一个巨大的仓库中存放和寻找物品。这个仓库就是数据结…

机器学习中的过拟合问题及应对策略:深入剖析与实战指南

在机器学习的领域中&#xff0c;过拟合是一个普遍而又棘手的问题。过拟合指的是模型在训练数据上表现优秀&#xff0c;但在未知或测试数据上表现不佳的现象。这通常是因为模型过于复杂&#xff0c;以至于“记住”了训练数据的噪声和细节&#xff0c;而非学习其内在规律和结构。…

立创·实战派ESP32-C3开发板 with lv_micropython

一、lv_micropython对驱动芯片的支持 ESP32-C3开发板的Display drivers:ST7789&#xff0c;Input drivers:FT6336&#xff0c;从LVGL的官方文档了解到lv_micropython包含了这两颗IC的驱动。 参考文档&#xff1a; lv_micropython already contains these drivers: 链接:Micro…

使用Python进行容器编排Docker Compose与Kubernetes的比较

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 随着容器化技术的普及&#xff0c;容器编排成为了管理和部署容器化应用程序的重要环节。在容…

jBPM的介绍

一、简介 jBPM&#xff08;Java Business Process Management&#xff09;是一个开源的业务流程管理框架&#xff0c;用于管理和执行业务流程。它提供了一个可视化的流程设计器&#xff0c;可以创建、模拟和部署业务流程&#xff0c;并提供了灵活的流程执行引擎。 jBPM可以帮…

【Go语言快速上手(三)】数组, 切片与映射

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; GO快速上手 1. 前言2. 数组详解3. 切…

中栈内联(THE MID-STACK INLINER)优化

THE MID-STACK INLINER 直译为“中栈内联”&#xff0c;属于一种更为新进的内联策略。内联&#xff08;InLining&#xff09;的工作原理是将对一个函数的调用展开为函数本身的代码&#xff0c;通过内联减少函数调用的开销&#xff0c;也给编译器带来进一步优化代码的机会。那么…

AI大模型探索之路-实战篇3:基于私有模型GLM-企业级知识库开发实战

文章目录 前言概述一、本地知识库核心架构回顾&#xff08;RAG&#xff09;1. 知识数据向量化2. 知识数据检索返回 二、大模型选择1. 模型选择标准2. ChatGLM3-6B 三、Embedding模型选择四、改造后的技术选型五、资源准备1. 安装git-lfs2. 下载GLM模型3. 下载Embeding模型 六、…

Android Studio超级详细讲解下载、安装配置教程(建议收藏)

博主介绍&#xff1a;✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神&#xff0c;答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战&#xff0c;深受全网粉丝喜爱与支持✌有…

c语言利用控制台实现贪吃蛇

使用控制台实现贪吃蛇需要的技能加点&#xff1a; 控制台设置&#xff08;包含于stdlib.h&#xff09;&#xff1a; 定义命令行窗口高/宽&#xff1a; system("mode con cols100 lines30"); system() 函数是一个C标准库函数&#xff0c;它允许程序执行操作系统命令…

深度学习Day-14:RNN实现心脏病预测

&#x1f368; 本文为&#xff1a;[&#x1f517;365天深度学习训练营] 中的学习记录博客 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制] 要求&#xff1a; 本地读取并加载数据&#xff1b;了解循环神经网络RNN的构建过程&#xff1b;测试集accuracy达到87%…

Linux--Linux常用命令

Linux常用命令 前言Linux命令格式命令讲解1、ls:查看当前目录下所有的内容语法:ls[-al][dir]2、pwd: 查看当前所在目录3、cd : 切换目录4、touch[文件名] : 如果文件不存在新建文件5、mkdir: 创建目录6、rm: 删除指定文件7、rmdir: 删除空目录8、cat:用于显示文件内容9、m…