当前位置: 首页 > news >正文

C++【类和对象】(一)

文章目录

  • 前言
  • 1.类的定义
    • 1.1类定义格式
    • 1.2 访问限定符
    • 1.3 类域
  • 2. 实例化
    • 2.1 实例化的概念
    • 2.2 对象大小
  • 3.this指针
  • 结语

前言

在前文我们讲解了C++基础语法知识。本文将会讲解C++的类和对象。

1.类的定义

1.1类定义格式

class name
{}
  • class为定义类的关键字,name为类的名字,{}中为类的主体,注意{}后面的;不能省略。
  • 类主体中的内容也称为类的成员,类中的变量也被称为类的属性或者成员变量;类中的函数被称为类的方法或者成员函数。
  • 我们为了区分成员变量,一般会在成员变量上加一个特殊标记,例如在成员变量前面或后面加一个_或者my,但C++并不强制要求你要这样写,这只是一些惯例。
  • C++中struct也可以定义成类,C++兼容了C语言的用法,同时也把struct升级成了类,明显的变化就是struct也可以定义函数,但一般情况下我们还是使用class来定义类
  • 定义在类里面的函数默认是inline内联函数。
#include<iostream>
using namespace std;class cla
{int Func(int x, int y){return x + y;}int x;int y;
};struct str
{int Func(int x, int y){return x + y;}int x;int y;
};

接下来我们来使用一下类

#include<iostream>
using namespace std;class cla
{int Func(int x, int y){return x + y;}int x;int y;
};int main()
{cla c1;c1.x = 10;return 0;
}

在这里插入图片描述
这里我们可以看到发生了报错,那这是为什么呢?
接下来我们就需要了解访问限定符了。

1.2 访问限定符

  • C++的一种实现封装的方法,用类将对象的属性与方法结合到一起,让对象变得更方便,通过访问权限可以选择性的将接口提供给外部的用户使用。
  • C++一共有三个访问限定符,public(公用)、private(私有)、protected(保护);public修饰的成员在类外可被直接访问;private和protection修饰的成员则在类外被直接访问,private和protection目前的功能是一样的,直到继承才能体现出他们的区别。
    在这里插入图片描述
  • 访问权限也有自己的作用域,访问权限的作用域是从访问限定符出现的位置开始,直到下一个访问限定符出现位置,而过后续没有其他的访问限定符,则访问权限遇到 } 即类的结束。
    在这里插入图片描述
  • class定义时默认的访问限定符是private,而struct默认public。
struct str
{int Func(){return _x + _y;}int _x;int _y;
}; 
class cla
{int Func(){return _x + _y;}int _x;int _y;
};int main()
{cla c1;str s1;c1.Func();// error C2248: “cla::Func”: 无法访问 private 成员s1.Func();
}

1.3 类域

  • 类也定义了一个新的作用域,类的所以成员都在类的作用域中,在类外定义成员时,需要使用::作用域操作符来指明成员是属于哪个类域的。
#include<iostream>
using namespace std;class cla
{
public:void Func();private:int _x;int _y;
};void cla::Func()
{_x = 10;//函数主体……
}
int main()
{cla c1;c1.Func();
}

2. 实例化

2.1 实例化的概念

  • 用类类型在物理内存中建立对象的过程,称为类实例化出对象
  • 可以把类想象成一个图纸,他只限定了类有哪些成员变量,这些成员变量只是声明,还没有分配空间,当你用类实例化出对象时,才会分配空间。
  • ⼀个类可以实例化出多个对象,实例化出的对象才会占用实际的物理空间,存储类成员变量。
#include<iostream>
using namespace std;//日期类
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和d2Date d1;Date d2;d1.Init(2024, 9, 10);d2.Init(2024, 9, 20);d1.Print();d2.Print();return 0;
}

2.2 对象大小

我们简单回顾一下,我们之前学过C语言的结构体,结构体里面存有成员变量,结构体的成员变量要按照内存对齐的去进行计算大小,C++的类也是遵循这个规则。
但不同的是,C++支持类内拥有成员函数,那这些成员函数要不要参与计算呢,答案是不用的;首先函数被编译后是一段指令,对象是无法存储这些指令的,这些指令会存储在一个单独的区域(代码段),如果对象非要存储,那也只能存储成员函数的指针。
那我们再分析一下,对象中的成员函数指针有存储的必要吗?我们那Date类举例,Date实例化了d1和d2两个对象,他们都有自己独立的成员变量(_year, _month, _day),这些自然是要存储的,但是我们看看d1和d2的成员函数指针(通过反汇编来看)。
d1的init
Init的第一句代码的地址
在这里插入图片描述
d2的init

可以看到他们是一样的,这样存储在对象里面就太浪费了。假设我用Date实例化了100个对象,那么相同的成员函数指针就会被重复存储100次,这就太浪费了。
这⾥需要再额外哆嗦⼀下,其实函数指针是不需要存储的,函数指针是⼀个地址,调用函数被编译成汇编指令[call 地址]。

所以C++计算类的大小是只计算成员变量,计算时要遵循内存对齐的规则。
内存对齐的规则

  • 第一个成员在与结构体偏移量为0的地址处
  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
  • 对齐数 = 编译器默认的一个对齐数 与 该成员变量的大小 进行比较得出的较小值
  • 类/结构体的总大小为:最大对齐数(成员变量中对齐数最大)的整数倍
  • 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
  • 细节可以看之前的博客:C语言自定义类型【结构体】中的结构体的内存对齐。
#include<iostream>
using namespace std;
class A
{void Func(){;}char c;int a;
};class B
{};class C
{void Func(){;}
};int main()
{A a;B b;C c;cout <<"class A:" << sizeof(a) << endl;cout <<"class B:" << sizeof(b) << endl;cout <<"class C:" << sizeof(c) << endl;return 0;
}

在这里插入图片描述
我们可以看到B、C类明明没有成员变量,可大小却是1,为什么明明没有成员变量还要给一个字节呢?因为如果一个字节都不给,你怎么表示这个类是存在的!所以这里给一个字节,纯粹是为了占位,表示对象是存在的。

3.this指针

我们拿Date类来举例,我们用同一个类模板实例化了两个不同的对象(d1和d2),但是我们调用的函数是同一个函数,而且我们也能看到这个函数把d1和d2给区分了,这是为什么呢?其实这里是C++给了个隐含的this指针,来解决区分的问题。

  1. 编译器编译后,类的成员函数会在形参的第一个位置,增加一个当前类类型的指针,叫做this指针。比如Date类的Init的真实原型为:void Init(Date * const this, int year, int month, int day)
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;
};
  1. 类的成员函数访问成员变量,本质还是通过this指针来访问的,例如Init函数给_year,显示的写就是this->_year = year;
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){_year = year;this->_month = month;this->_day = day;}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
  1. C++规定,不能在实参和形参的位置显示的写this指针,但是可以在函数内显示的使用this指针

结语

本文初步讲解了c++的类和对象,讲解了类的定义、实例化、类的大小和this指针。

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言,也可以前往我的主页看更多好文哦(点击此处跳转到主页)。
如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux实用操作
  • OpenCV库学习之cv2.VideoWriter(函数)
  • 掌握 Spring:从新手到高手的常见问题汇总
  • OpenCV特征检测(2)边缘检测函数Canny()的使用
  • Spring在不同类型之间也能相互拷贝?
  • 【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL77
  • Linux 生成 git ssh 公钥
  • Linux 内核的版本控制
  • linux-系统备份与恢复-系统恢复
  • Redis主要问题
  • C语言习题~day25
  • mac 怎么查看CPU核数
  • Arthas jvm(查看当前JVM的信息)
  • 2024年全新deepfacelive如何对应使用直播伴侣-腾讯会议等第三方软件
  • 毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • AWS实战 - 利用IAM对S3做访问控制
  • Django 博客开发教程 16 - 统计文章阅读量
  • Java深入 - 深入理解Java集合
  • linux学习笔记
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • socket.io+express实现聊天室的思考(三)
  • Vue 2.3、2.4 知识点小结
  • vue2.0项目引入element-ui
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 产品三维模型在线预览
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 深度解析利用ES6进行Promise封装总结
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • mysql面试题分组并合并列
  • 整理一些计算机基础知识!
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​批处理文件中的errorlevel用法
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • $(function(){})与(function($){....})(jQuery)的区别
  • (4)STL算法之比较
  • (7)摄像机和云台
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (十六)、把镜像推送到私有化 Docker 仓库
  • (四)JPA - JQPL 实现增删改查
  • (一)Neo4j下载安装以及初次使用
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • (自用)gtest单元测试
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .Net Winform开发笔记(一)
  • .net 后台导出excel ,word