C++ 类和对象(上)

ops/2024/10/11 11:18:21/

文章目录

  • 类的定义及访问限定符
    • 类域
      • 类的实例化
        • 对象的大小
          • this指针

类的定义及访问限定符

类的格式:

  • class为类的关键字,class + 类的名字(自定义)+ {} + ;
  • 类中可以定义成员变量也可以定义成员函数,在类中定义的成员函数默认是内联函数,变量为类的属性,函数为类的方法
  • 类的成员在定义时可加上一些特殊的标识符,便于区分,也可不加

例:

#include <iostream>
using std::cout;
using std::endl;
//用类来定义一个栈
class stack // stack为类的名字
{//类的成员函数void Init(int capacity = 10){_arr = (int*)malloc(sizeof(int) * capacity);if(_arr == nullptr){perror("malloc fail!");exit(-1);}_capacity = capacity; //有了特殊标识符就可区分,哪个是成员变量,哪个是形参了_top = 0;}//类的成员变量int* _arr; // "_"为特殊标识符int _capacity;int _top;
};
int main()
{//...return 0;
}

类与结构体:
从上面的代码可以看到,类的格式与C语言中的结构体相似,但是C语言中的结构体成员只允许有变量,而不能有函数,所以C++对C的结构体进行了“升级”,在C++中,也可以用结构体来定义类

在这里插入图片描述
通过上面的代码,C++也可以用结构体定义类,但更多的时候,大家还是选择用class来定义

类的访问与访问限定符的关系:

  • 对类进行访问时,首先要定义类的对象,对象其实就是C语言中的变量
  • 定义的对象的类型就是自定义的类名
  • 访问类的成员与访问结构体的成员是一样的,用到“ . ”操作符或者“->”操作符
class A
{void Print(){cout << "hello world!" << endl;}int _a;
};
int main()
{A a; // a为类定义出来的对象,类名就是该对象的类型,类和对象也由此体现了出来a.Print(); // 通过“.”操作符来访问类的成员函数return 0;
}

接着来看,若将该代码放到本地来运行,结果如下:

在这里插入图片描述
出现这样的错误与访问限定符有关,介绍一下访问限定符:

  • public
  • private
  • protected

这三个就是访问限定符,作用在类中,public表示可直接对类进行访问,private 和 protected 表示不可直接对类进行访问;限定符的作用域是从该访问限定符开始到下一个访问限定符出现为止,或者没有访问限定符的出现,直接到类的作用域结束;class在没有定义访问限定符时,默认是private,而struct默认是public,所以这也是为什么上面的代码会出现访问错误的原因,上面的成员函数和成员变量被作用在private中,不可直接对其进行访问;一般的,成员变量被设在private 和protected 中,而需要给别人使用的成员函数就被设为protected

类域

类域定义了一个新的作用域,类的成员变量和成员函数都放在作用域中,与命名空间的访问类似,在类体外访问域里的成员时,需要用到“: :”域作用限定符,指明要访问的成员属于哪个类域,类域影响的是编译的查找规则
在这里插入图片描述
如上图所示,在不同的两个及以上的文件中,定义类的成员函数时,就需用到域作用限定符,防止在同一个文件下出现两个同名函数时,定义的时候产生矛盾。如,在stack.h中再定义一个队列的类,类中的初始化成员函数名也是Init时,在.cpp文件中定义时,没有明确是哪个类域的初始化,就会产生矛盾,定义成员变量时,亦如此

类的实例化

概念:用类的类型创建对象的过程,就叫作类的实例化

include <iostream>
using std::cout;
using std::endl;
class A
{
public:void Print(int x){_a = x;cout << _a << endl;}
private:int _a;
};
int main()
{// 这就是实例化出对象// 用类的类型A创建出来的对象a1,a2,a3A a1; A a2;A a3;return 0;
}

类相当于一个模型一样的东西,限定了类中有哪些成员变量,这写成员变量只是声明,并没有分配空间,只有用类实例化出对象时,才会分配空间(注:没有分配空间的是声明,分配了空间的才是定义),打个比方,创建出来的类相当于一张建房子要用到的图纸,图纸上有房子的整体外观,房子面积多大,高是多少,各种各样的数据,然后通过图纸来建房,建出来的房子就是通过图纸实例化出来的。类的成员变量没有空间,它就相当于图纸,图纸里的房子只是模板,不能住人,而只有实例化出来的对象才需要分配空间,通过图纸建出来的房子才可以住人,才需要空间。

对象的大小

在这里插入图片描述
通过上面的打印结果可知:

  • 对象的大小只考虑成员变量,不考虑成员函数
  • 对象的大小遵循内存对齐的规则

为什么不考虑成员函数?

对象的大小只考虑成员变量,是因为每个对象所要存储的数据不同,所以要为每个变量开辟空间,来存储数据,而函数在被定义编译时,就已经确定了,编译完之后会生成一条条指令,第一条指令就是函数的地址,而每个对象在调用函数时,都会通过函数的地址进行调用,所以每个对象所调用的函数都是同一个函数,若每个对象中都存储一个相同的函数,就显得多余了,所以系统会将函数放到一个公共的区域,每个对象需要调用时,就可直接调用

在这里插入图片描述
从图中可以看到,d1和d2同时调用Init函数,call指令就是进入函数的指令,且两个对象的call指令的地址都相同

为什么要内存对齐?

在这里插入图片描述
所以由上图可知,内存对齐是为了提高读取数据的速度

this指针

在这里插入图片描述
从上面的图片中看到,不同的对象调用的函数是相同的,那为什么打印出来的数据却不同呢?出现这样的结果是因为this指针在里面起到了作用

  • 编译器编译后,默认会在类的成员函数的形参的第一个位置增加一个当前类型的this指针
class date
{
public:void Init(int year, int month, int day)// 本质:void Init(date* const this,int year, int month, int day){_year = year;_month = month;_day = day;}void Print()// 本质:void Print(date* const this){cout << _year << "/" << _month << "/" << _day << endl;// 本质:cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main()
{date d1;date d2;d1.Init(2024, 12, 19); //本质:d1.Init(&d1,2024,12,19);d2.Init(2024, 8, 8);//本质:d2.Init(&d2,2024,8,8);d1.Print(); // 本质:d1.Print(&d1);d2.Print();// 本质:d2.Print(&d1);return 0;
}

正因为有了this指针,所以才能做到打印出来的数据不同

  • 在类的成员函数中访问成员变量时,本质上都是通过this指针来进行访问的

从上面的代码就了知道了,但大多数情况下,this指针是不会被写出来的

  • C++规定不能在实参和形参的位置显示地写this指针,但在成员函数体中可显示

在这里插入图片描述
可看到显示this指针之后出现了错误,但在函数体中是可以显示的


http://www.ppmy.cn/ops/92011.html

相关文章

阿里云万网推出首个域名AI大模型智能体应用,上线“.ai”等40个全新域名后缀

中国域名保有量3160万&#xff0c;以9.4%的份额位居全球第二。 域名资源越来越紧张&#xff0c;运维越来越复杂&#xff0c;面对的网络攻击也越来越频繁&#xff0c;都给这一领域提出了更大挑战。 8月8日&#xff0c;在阿里云万网焕新发布会上&#xff0c;阿里云宣布域名产品服…

数据库连接池的深入学习

为什么需要数据库连接池&#xff1f; 正常操作数据库需要对其进行连接&#xff0c;访问数据库&#xff0c;执行sql语句&#xff0c;断开连接。 创建数据库连接是一个昂贵的过程&#xff0c;在高并发的情况下&#xff0c;频繁的创建数据库的连接可能会导致数据库宕机。 有了连…

DevOps 相关知识点总结

1. 请简要解释 DevOps 的概念和核心原则。 - DevOps 是一种将软件开发&#xff08;Dev&#xff09;和 IT 运维&#xff08;Ops&#xff09;相结合的理念和方法&#xff0c;旨在缩短开发周期、提高软件交付质量和效率&#xff0c;促进开发、运维和其他相关部门之间的沟通、协作…

多尺度病理图像纹理特征作为肺腺癌预后预测的新指标|文献精读·24-08-09

小罗碎碎念 这一期推文分享的文献是2022年发表于 Journal of Translational Medicine 的一篇文章&#xff0c;目前IF6.1。 这篇文章值得刚入门病理AI领域的老师/同学仔细研读&#xff0c;因为思路清晰&#xff0c;该讲到的流程基本都涉及了&#xff0c;详细讲述了病理图像的各种…

架构师软考-每日两道单选题8

第15题 单选题 在数字孪生生态系统中&#xff0c;&#xff08; &#xff09;包括描述、诊断、预测、决策四个方面。 A 数据互动层 B 模型构建层 C 仿真分析层 D 共性应用层 解析 共性应用层包括描述、诊断、预测、决策四个方面。在数字孪生生态系统中&#xff0c;共性应用层…

ansible ---- ansible.builtin.command

一、详解 command模块是ansible-core核心模块的一部分&#xff0c;大多数情况下可以使用简化名command&#xff1b;该命令会被执行在所有选择的机器上。 注意事项 1、该命令并不会通过shell执行&#xff0c;所以对于环境变量$HOSTNAME以及一些" *", “<”, “&g…

CnosDB 元数据集群 – 分布式时序数据库的大脑

CnosDB 是一个分布式时序数据库系统&#xff0c;其中元数据集群是核心组件之一&#xff0c;负责管理整个集群的元数据信息。 1. 概述 CnosDB 是一个分布式时序数据库系统&#xff0c;其中元数据集群是核心组件之一&#xff0c;负责管理整个集群的元数据信息。元数据包括数据库…

【leetcode】根据二叉树创建字符串、二叉树的前中后遍历(非递归链表实现二叉树)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构、LeetCode专栏 &#x1f4da;本系…