目录
💕1.C++中结构体的优化
💕2.类的定义
💕3.类与结构体的不同点
💕4.访问限定符(public,private,protected)
💕5.类域
💕6.类的实例化
💕7.类的字节大小
💕8.类的字节大小特例
💕9.this指针
(最新更新时间——2025.1.13)
因为困难多壮志,不教红尘惑坚心
今身暂且栖草头,他日狂歌踏山河
💕1.C++中结构体的优化
在C++中,结构体的使用得到了优化,具体优化了什么呢?请看以下代码->:
struct student { int age; double num; }; int main() { struct student s1;//C语言中书写,C++也兼容 student s1;//C++中优化 return 0; }
我们在C语言中书写时,需要把struct把写上,而在C++中得到了优化,不需要写struct,直接写结构体的名称也可以使用
同时我们也可以在struct中定义函数
struct student { int age; double num; int add(int a, int b) { return a + b; } }; int main() { student s1;//C++中优化 cout<<s1.add(10, 20);//输出30 return 0; }
💕2.类的定义
我们回到正题,什么是类?
类其实就是结构体的优化,我们将struct 更改为 class,就属于变为了类
先看一段代码,在这串代码中,class 是类的关键字,student 是类的名字
{ }为类的主体,类中的变量称为类的属性或成员变量,
class student { //类的⽅法或者成员函数 int add(int a, int b) { return a + b; } //类的属性或者成员变量 int age; double num; }; int main() { student s1;//创建类变量s1 }
就此看来,类与结构体还没有不同点,那么不同点在哪呢?
💕3.类与结构体的不同点
类中的成员函数是与成员变量密切相关的,即同一类中,成员函数可以给成员变量赋值,并且成员变量也可以作为成员函数的参数,我们举个例子->:
如图所示,即使我们不进行传参,成员函数内也可以找到类中对应的成员变量,而结构体却不可以
因此->:在类中创建的成员变量,在类中是直接可以用的
💕4.访问限定符(public,private,protected)
在C++中,类的定义中新建了三种权限关系,分别是public,private,与protected
这些的意义是什么呢?
C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限
选择性的将其接⼝提供给外部的⽤⼾使⽤
public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访 问,protected和private是⼀样的,以后继承章节才能体现出他们的区别,接下来是代码举例->:
我们可以发现,我们在类中的成员函数设置为private,只可以在类的内部使用,那么在类的外部就不能使用这些成员函数,这就是private的作用
那如果把它换成public呢?
效果如下->:更换成public后,权限被更改为公有的,在类外面也可以进行使用
如果我们访问限定符什么都不写的话,系统会默认全部设为private
💕5.类域
讲类域之前,我们先讲一个简单的例子
class student { int age; int year; }; int main() { }
这是的类叫做类的声明还是定义?
答案是声明,类的定义是会开创出空间的,而此时的类没有任何的变量并不会开创空间,所以此时叫做类的定义,那既然是类的定义,那可不可以写在 .h 文件中,答案是可以的,接下来请看代码->:
.h文件>:
#pragma once #include<iostream> #include"abc.h" using namespace std; class Date{ public: void Init(int year, int month, int day); int _year; int _month; int _day; };
我们可以在.h中实现类的声明,那类中成员函数的实现怎么办,我们以往的经验是写在函数功能实现的.c文件中,在C++中也是一样的,只不过有一点不同
函数实现文件.c->:
#define _CRT_SECURE_NO_WARNINGS #include"achie.h" void Date:: Init(int year, int month, int day) { _year = year; _month = month; _day = day; }
在这些代码中,我们看到了类中成员函数的实现,有许多人都会注意到了 Date:: ,这是什么意思?这是因为类域的存在,我们知道函数的实现依靠的是函数的地址,而编译器寻找的方式是全局域,局部域,命名作用域与类域,我们的Init写在了类域中,编译器在全局域与局部域都找不到,而命名作用域与类域都是需要特殊指定的域,所以如果不声明编译器就找不到这个函数在哪,我们可以试一下不指定后的样子:
以下分别是.h与函数实现的.c文件中的图片,可以看到.h中说明找不到函数的定义,因为在函数实现.c文件中,并没有找到Init函数的地址
💕6.类的实例化
类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只 是声明,没有分配空间,⽤类实例化出对象时,才会分配空间
⼀个类可以实例化出多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量。打个⽐ ⽅:类实例化出对象就像现实中使⽤建筑设计图建造出房⼦,类就像是设计图,设计图规划了有多 少个房间,房间⼤⼩功能等,但是并没有实体的建筑存在,也不能住⼈,⽤设计图修建出房⼦,房 ⼦才能住⼈。同样类就像设计图⼀样,不能存储数据,实例化出的对象分配物理内存存储数据。
一个类可以实例出多个对象的代码演示->:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Date { public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day; }; int main() { Date a1; Date a2; Date a3; }
这里就是类与对象的关系,一个类可以有多个对象,如果有拿这段代码去运行而报错的同志,那就是因为对象创建出来后没有手动初始化,注意是手动(后面讲)
💕7.类的字节大小
类的字节大小是怎么计算的,其实与我们在C语言中学的结构体极其类似,具体在哪不同,我们接着看->:
我们可以看到是12个字节,为什么?
其实这里与我们在C语言中学习的结构体内存存储方式基本相同,如果不懂的具体请看这篇文章,我们这里只讲不同点->:
C语言结构体详解(超全)简单易懂(代码+万字文字+画图讲解)
不同点在于->:当我们计算类的字节大小时,我们会思考,类中的函数存储在哪?
⾸先函数被编译后是⼀段指令,对象中没办法存储,因此这些指令存储在⼀个单独的区域(代码段)
也就是说明类中的成员函数存储在公共代码区,这也意味着每个对象所使用的函数是共同的,并不会因为每有一个类就创建一个它自己的函数,它与其他对象所使用的函数是共同的
我们知道,函数的使用是相当频繁地,如果一个对象使用100次函数,那么创建出来的空间是非常大的,因此函数的地址会存放在公共代码区,避免空间重复,浪费空间
注意->:对象中的每个成员变量是独立的成员变量
💕8.类的字节大小特例
为什么输出的字节是1呢?
类中的成员变量为空,不应该输出0吗?
其实这个1字节是为了识别出类而开辟的,所以是1
那这样呢?
这样输出的1跟之前所输出1的原因是相同的,都是为了识别出类的存在
💕9.this指针
在类的函数中,其实有一个隐藏的 this 指针,什么是隐藏的 this 指针?
其实当我们调用类中的成员函数时,会将这个对象的地址传输过去,什么意思?请看代码->:
在我们调用函数时,就会将对象的地址传输过去,并在成员函数的形参处用Date* const this来接受,为什么会报错?这是因为->:
C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内使⽤this指针,什么意思?请看下图->:
这里的this可以写也可以不写,主要是为了演示一遍,这里的this指的就是对象a1的地址
小题思考->:
我们思考一下,下面这串代码的运行结果是什么->:
#include<iostream> using namespace std; //A.编译报错 B.运行崩溃 C.正常运行 class A { public: void Print() { cout << "A::Print()" << endl; } private: int _a; }; int main() { A* p = nullptr; p->Print(); return 0; }
其实是正常运行,在这里传递的是p,也就是一级指针,传空指针是没有问题的,空指针只有在解引用时候才会报错,而这里并没有进行解引用,也就是说会正常运行
再来看一道
#include<iostream> using namespace std; //A.编译报错 B.运行崩溃 C.正常运行 class A { public: void Print() { cout << "A::Print()" << endl; cout << _a << endl; } private: int _a; }; int main() { A* p = nullptr; p->Print(); return 0; }
这道题就不会正常运行了,而是运行崩溃,因为从语法上看,
this->a
等价于(*this).a
。这里的*this
就是对this
指针的解引用,它获取了this
所指向的对象本身,然后通过.
操作符访问该对象的成员变量a
空指针被解引用了,所以运行崩溃了
最后一道思考->:
3. this指针存在内存哪个区域的 () A. 栈 B.堆 C.静态区 D.常量区 E.对象⾥⾯
这里的答案是栈区,因为this指针是形参,而形参是存储在栈区的