C++中 面向对象三大特性 : 封装、继承、多态 。今天学习类的相关知识,其是封装的体现之一。
class Stack //关键字和名字
{
//成员函数
void Init()
{
//...
}
private:
// 成员变量
int* _array;
size_t _capacity;
size_t _top;
}; //不能缺;
#include<iostream>
using namespace std;
class Day
{
public:
int GetYear() //在类里面访问私有成员变量
{
return _year;
}
private:
int _year = 1;
};
int main()
{
Day d;//实例化
cout << d.GetYear() << endl; //调用函数接口
return 0;
}
看完是不是觉得很抽象,跟没看一样?打个比方
在日常生活中,房子是司空见惯的。而房子的设计需要设计图,即 设计图 --> 房子 。
同理,在实例化对象当中,类就相当于是设计图(已经有人写好了,可供使用),而实例化对象就相当于房子。 即 类 --> 实例化对象。
既然类能实例化对象,开了空间意味着需要知道对象有多大,对象中肯定包含成员变量,同时要明白内存是如何对齐的。
• 第一个成员在与结构体偏移量为0的地址处。
• 对齐数 = 编译器默认的对齐数 与 该成员大小的较小值。(VS中默认的对齐数为8)
若要修改编译器默认对齐数,则添上如下代码
#pragma pack(4)//设置默认对齐数为4
#pragma pack()//取消设置的对齐数
• 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
• 结构体总大小为:最大对齐数的整数倍。
• 如果嵌套了结构体的情况,嵌套的结构体对⻬到自己的最⼤对⻬数的整数倍处,结构体的整体大小就是所有最大对⻬数(含嵌套结构体的对⻬数)的整数倍。
此结构体对象大小为多少呢?
struct A
{
int a;
int b;
char c;
};
根据内存对齐规则:第一个成员a在与结构体偏移量为0的地址处,占4个字节。成员b先对齐到对齐数的整数倍处,占4个字节;成员c同理。总占9个自己,由于需要对齐到最大对齐数的整数倍,因此结构体总大小为12。
那结构体内没有成员呢?
struct A
{
};
运行后发现 A类对象的大小是1 ,为什么没有成员变量还要给1个字节呢?因为如果一个字节都不给,表示不了对象存在过,作用是为了占位标识对象存在。
疑惑 --> 为什么会存在内存对齐呢?
内存对齐是为了提高访问效率。
那么成员函数是否包含呢?不包含
了解:首先函数被编译后是一段指令,对象中没办法存储,这些指令存储在一个单独的区域(代码段),那么对象中非要存储的话,只能是成员函数的指针。再分析一下,对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各自独立的成员变量存储各自的数据,但是d1和d2的成员函数Init指针却是一样的,存储在对象中就浪费了。如果用Date实例化100个对象,那么成员函数指针就重复存储100次,太浪费了。 这里需要再额外哆嗦⼀下,其实函数指针是不需要存储的,函数指针是⼀个地址,调用函数被编译成汇编指令[call 地址], 其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址。
在C语言版本中,在实现对应函数功能时,我们需要把对象的参数传过去,以便知道是哪个对象在调用对应函数。从下面程序中,每次都需要将对象的地址传过去,是非常繁琐和不方便的。因此在C++中引入了一个新的语法 --> this 指针。
#include<iostream>
using namespace std;
class Date
{
public:
//成员变量
int _year;
int _month;
int _day;
};
void Init(Date* const d, int year, int month, int day)
{
d->_year = year;
d->_month = month;
d->_day = day;
}
void Print(Date* const d)
{
cout << d->_year << "-" << d->_month << "-" << d->_day << endl;
}
int main()
{
Date d1;
Date d2;
Init(&d1,2025, 2, 28);
Init(&d2,2024, 1, 14);
Print(&d1);
Print(&d2);
return 0;
}
• 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加一个当前类类型的指针,叫做this 指针。
void Init(int year,int month, int day)//隐藏this指针
其原型为
void Init(Date* const this, int year,int month, int day)
这里补充一点,this指针加const的原因是为了使代码更加健壮,其目的是不改变this指针变量本身,可以改变this指针指向的内容,
• 类的成员函数中访问成员变量,本质都是通过this指针访问的。
• C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。
void Init(int year, int month, int day)
{
//显示传this指针
this->_year = year;
this->_month = month;
this->_day = day;
}
设计出这个语法大大方便了程序员,将工作交给编译器来处理,并且使代码简洁且容易理解。如下便是C++版本中this指针作用的程序。
#include<iostream>
using namespace std;
class Date
{
public:
//成员函数
void Init(int year,int month,int day)//隐藏的第一个参数为this指针
{
//this->_year=year;//可在函数内显示调用
_year = year;
_month = month;;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
//成员变量
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
d1.Init(2025, 2, 28);
d2.Init(2024, 1, 14);
d1.Print();
d2.Print();
return 0;
}