🧇个人主页: 起名字真南
🌭个人专栏:【数据结构初阶】 【C语言】 【C++】
目录
- 1 类的定义
- 1.1 类定义格式
- 1.1.1 Stack类
- 1.1.2 Date类
- 1.1.3 Struct格式
- 1.2 访问限定符
- 1.3 类域
- 2 实例化
- 2.2 对象大小
- 3 this指针
1 类的定义
1.1 类定义格式
1 class为定义类的关键字,Stack为类的名字,{}内为类的主体,并且类在定义的时候不能省略后面的分号,类体中的内容称为类的成员,类中的变量叫做类的属性,也被称为成员变量,类中的函数叫做类的方法也被称为成员函数。
2 为了区分成员变量和全局变量以及主函数之间的变量在类中定义成员变量的时候可以加上下划线 ‘ _ ’,
3 C++中struct也可以定义类,并且C++兼容C语言中struct结构体的用法,并且升级为类,最大的区别便是可以在内部定义函数。
4 定义在类中的成员函数默认为inline
1.1.1 Stack类
#include<iostream>
using namespace std;
#include<assert.h>
class Stack
{
public:
//成员函数
void Init(int n )
{
arr = (int*)malloc(sizeof(int) * n);
if (arr == nullptr)
{
perror("开辟空间出现错误!");
return;
}
capacity = n;
top = 0;
}
void Push(int x)
{
arr[top++] = x;
}
int Top()
{
assert(arr);
return arr[top - 1];
}
void Destroy()
{
free(arr);
capacity = 0;
top = 0;
}
private:
int* arr;
size_t capacity;
size_t top;
};
int main()
{
Stack st1;
st1.Init(4);
st1.Push(1);
st1.Push(2);
st1.Push(3);
st1.Push(4);
cout << st1.Top() << endl;
return 0;
}
1.1.2 Date类
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//区分成员变量一般在名字前面加上下划线
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2024, 9, 20);
return 0;
}
1.1.3 Struct格式
#include<iostream>
using namespace std;
#include<assert.h>
//C语言环境下struct的定义
typedef struct ListNodeC
{
ST* next;
// struct ListNode* next;
int val;
}ST;
struct ListNodeCpp
{
void Init(int x)
{
next = nullptr;
val = 0;
}
ListNodeCpp* next;
int val;
};
在C++中不需要typedef只需要ListNodeCpp就可以代表这个类型,并且在struct类下里面的成员函数和成员变量默认的访问权限都是public。
1.2 访问限定符
- C++实现封装的一种方式,就是用类把成员变量和成员函数结合在一块,然后通过访问权限选择性的将接口提供给外部的用户进行使用
- public修饰的成员变量和函数是可以被任意访问的但是用private/protected修饰的则不能直接进行访问
- class类在默认的情况下都是用private来修饰,struct在默认的情况下都是public
- 访问限定符的权限以及作用范围都是从第一个访问限定符开始到第二个访问限定符之前,或者直接到 “ } ”。
1.3 类域
- 类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员变量的时候需要使用 “::” 作用域操作符来指定该成员属于那个类域
- 类域影响的是编译的查找规则,例如在下面的代码中如果在定义函数Init的时候没有指定类域就会出现访问不到Stack类中数据的错误,如果不指定类域那么Init就会被编译器认为是全局函数找不到类中的成员变量。
#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 (array == nullptr)
{
perror("malloc fail");
return;
}
capacity = n;
top = 0;
}
int main()
{
Stack st;
st.Init();
return 0;
}
2 实例化
- 用类类型在物理内存中创建对象的过程叫做实例化对象。
- 在类中的成员变量只是声明,并没有分配出空间,通过类进行实例化的对象才会分配空间
- 一个类可以实例化出多个对象,实例化出来的对象占用实际的物理内存空间,存储成员变量。
class Date
{
public:
void Init(size_t year = 2024, size_t month = 10, size_t day = 5)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
//只有声明,并没有分配空间
size_t _year;
size_t _month;
size_t _day;
};
int main()
{
//实例化出两个对象 d1 d2
Date d1;
d1.Init();
d1.print();
Date d2;
d2.Init(1000,10,10);
d2.print();
return 0;
}
2.2 对象大小
内存对齐规则
- 第一个成员在与结构体偏移量为0的地址处
- 其他成员变量要对齐到对齐数的整数倍的地址处
- 对齐数 = 编译器默认的对齐数和成员变量大小的较小值
- vs中默认对齐数的大小是8
- 结构体的总大小为:最大对齐数(所有变量类型最大者与默认对齐数取最小)的整数倍
- 如果嵌套了结构体的情况下,嵌套的结构体对齐到自己最大对齐数的整数倍,整个结构体的大小就是所有最大对齐数的整数倍.
class A
{
public:
void Init()
{
}
private:
char _ch;
int _i;
};
class B
{
public:
void Init()
{
}
};
class C
{
};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}
将上面的代码运行结果展示
我们可以看到输出的结果是 8 1 1,说明a b c 的大小分别是 8 1 1,那么这个结果是怎么算出来的呢?
在A类型中最大对齐数为4,是整形int的大小,A中有两个类型另一个是char,char的大小是一个字节,int是四个字节加起来就是五个字节,4的整数倍是8正好大于5所以a对象的大小就是8,但是B C 的大小为什么是1呢?为什么没有成员变量还还有一个字节呢,其实这里的一个字节仅表示该类型存在纯粹是为了占位标识对象存在。
3 this指针
- 在Date类中有 Init 和 print两个成员函数,函数体中没有关于不同函数的区分但是我们在对d1 和d2两个对象进行初始化的时候是如何进行区分的呢?解决问题的方法就是在C++中提供了this指针。
- 编译器编译后,都会默认在类的成员函数的形参前面添加一个当前类类型的this指针,比如Date类中的Init成员函数的原型是:void Init(Date const this, int year, int month, int day)*
- 类中的成员函数访问成员变量本质上都是通过this指针进行访问的比如在Init中给year赋值本质上是:this->_year = year
- C++规定不能在实参和形参的位置上显示写this指针但是可以在函数体内显示使用this指针
class Date
{
public:
// void Init (const Date* this, size_t year, size_t month, size_t day)
void Init(size_t year = 2024, size_t month = 10, size_t day = 5)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
//只有声明,并没有分配空间
size_t _year;
size_t _month;
size_t _day;
};