class
为定义类的关键字,后有类名,类的主体存于{}
中;struct
用法,同时将struct
升级成了类的用法(更推荐类)举例代码:
class Stack
{
public:
// 成员函数
void Init(int n = 4)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
private:
// 成员变量
int* array;
size_t capacity;
size_t top;
}; // 分号不能省略
封装是OOP的一个基本原则,它指的是将数据(属性)和操作这些数据的代码(方法)组合在一起,形成一个单元。封装的主要目的是隐藏内部实现的细节,只暴露出一个可以被外界访问和操作的接口。
类会定义一个新的作用域,类的所有成员都在类的作用域中,在类外定义成员时需要用
::
作用域操作符指明成员属于哪个类域。
在类外定义成员函数:
#include<iostream>
using namespace std;
class Stack
{
public:
// 成员函数
void Init(int n = 4);
private:
// 成员变量
int* array;
size_t capacity;
size_t top;
};
// 声明和定义分离,需要指定类域
void Stack::Init(int n)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
类是一个蓝图或模板,它定义了一组属性(成员变量)和方法(成员函数),这些属性和方法共同描述了一类事物的特征和行为。而通过创建对象就可以将对象进行实例化,这一一种一对多的关系,一个类可以创造多个对象,每一个类都是一个个体实例,并不冲突。
// 如何实例化对象
// 定义一个日期类
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和d2
Date d1;
Date d2;
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}
对象中只存储成员变量,每个成员函数在对象调用的时候用的都是同一个指针来访问。对于对象的大小,要符合内存对齐的规则,关于内存对齐的详细运用理解可以点击蓝字阅读我的另一篇博客,具体的规则大概如下: • 第⼀个成员在与结构体偏移量为0的地址处。 • 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。 • 注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。 • VS中默认的对⻬数为8 • 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。 • 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。 •不要忘记内存对齐的目的:为了减少CPU访问内存次数,提高效率。
编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做
this指针
。⽐如Date类的Init的真实原型为,void Init(Date* const this, int year, int month, int day)
,但是C++规定不能在实参和形参位置上写this指针
,但是可以在函数体内显式使用this指针
。
_year
赋值, this->_year = year;
。所以通过this指针
可以对于一个对象的维护更加便捷。// 显式使用this指针
void Init(int year, int month, int day)
{
_year = year;
this->_month = month;
this->_day = day;
}
关于this指针
在内存上的存储位置:当成员函数被调用时,this 指针通常存储在调用栈上。调用栈是用于存储函数调用时的局部变量和状态信息的内存区域。