1.C语言中的类:
1.1 类的定义:
类其实是C语言中结构体的升级,与C语言相比,c++中的类不仅支持成员变量,还支持成员函数。
struct CppTest
{
int a;
void init() //在类中可以定义函数
{
a = 0;
next = nullptr;
}
int* next;
};
1.2 访问限定符
public,protected和private。
public限定符表明类中的所有成员都可以在类外被直接访问。
在此阶段protected和private的作用是一样的,都表明类中成员不能在类外被直接调用。
不管是什么限定符,在类内都是可以调用的。
1.3 类的作用域
在c++中只要有“{ }”就有域。
什么是影响生命周期的东西?
存在什么区域才是真正影响生命周期的东西。
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用::作用域操作符指明成员属于哪个作用域。
#辨别声明与定义
开了空间就是定义,没开空间就是声明。类和结构体一样,在定义一个结构体类型变量时并不会为成员开辟空间,只有用这个结构体类型(类)定义一个对象时才会为成员开辟空间,这个过程叫类的实例化。但是就算没有实例化对象,计算sizeof(类)并不会得到零,因为类的定义好比图纸,实例化对象就相当于根据这个图纸制造出房子,就算没有真实的房子也能根据图纸计算出房子应该有的大小。
int age; //定义
class person
{
public:
void printpersoninfo();//声明
private:
char name[20]; // 声明
char _gender[3];// 声明
int age;// 声明
};
所以在上述代码中,全局变量age开了空间是定义,而类中的成员全部是声明。
1.4 如何计算类的大小
因为类中可以包含成员函数,所以类大小的计算并不像结构体那么简单。
1.4.1 类中的对象存储可能有多种方式:
存储方式一:
这种方式弊端很明显,当定义多个对象时,虽然每个成员变量都是独立空间,但是每个对象调用的函数都是同一个,将这些函数存进去会大大浪费空间。
存储方式二:
这种方式把函数的地址存到一个函数表中,但是这里并没有采用这种方案,而是用了方式三。
存储方式三:
这种存储方式将函数放在公共代码区,当调用函数时并不会去对象的区域找,而是在编译时根据函数名直接call
class person
{
public:
void func()
{
cout << "func" << endl;
}
}; //这是类的定义
//看这段代码,猜猜运行结果是什么
person* ptr = nullptr;
ptr->func();
运行结果是正常运行,可以打印func。
这也验证了,调用类中的函数时编译器并不会去解引用ptr,否则解引用空指针会报错。
思考: 既然类中函数在公共代码区,为什么调用时还要加上对象名呢?
1.4.2 内存对齐规则
> 1. 第一个成员在与结构体偏移量为0的地址处。
> 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
> 注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
> VS中默认的对齐数为8
> 3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
> 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是
> 所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
既然函数并不占据空间,那么类的大小计算规则就和结构体一样了。以下面代码为例
class sample
{
public:
char i; // 1byte
int a; // 4byte
};
在vs下的默认对齐数是8byte,而类中最大的对齐数是4byte,所以对齐数设置成4byte。所以i放在偏移量为1的位置,a放在偏移量为4的位置,最终结果是8byte。
> #求特殊类型的大小
>
> 当定义一个空类型或者仅含有构造函数或者析构函数时,在vs下这些类型的大小均为1。因为类型必须在内存中占用一定空间,否则无法使用。所以VS给这些类型分配1byte空间。> #命名方法总结
>
> // 单词和单词之间首字母大写间隔 --驼峰法
>
> // 函数名,类名等所有单词首字母大写
>
> // 变量首字母小写,后面所有单词首字母大写
>
> // 成员变量,首单词前加 ' _'
>
> ————————————————————
>
> // 单词全部小写,单词之间用_分隔
## 2.this指针
```c++
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 a;
};
int main()
{
Date d1, d2;
d1.Init(2022, 1, 11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
```
观察上面代码,在Init函数中__year是否和成员变量_ _year是一块空间呢?但是这里还只是声明呀,哪里会开空间呢?怎么能够修改呢?
这里就涉及到了this指针,在C++语法中编译器会悄咪咪地给类的成员函数和main函数内调用成员函数传参部分加上this指针。
void Init(Date* const this, int year, int month, int day)//会加上this指针做形参
{
_year = year;
_month = month;
_day = day;
}
int main()
{
d1.Init(&d1, 2022, 1, 11);//会加上&对象名,对象名由前面的名字决定,所以就算成员函数在公共区,我们也要用对象名去调用。
d2.Init(&d2, 2022, 1, 12);
return 0;
}
ps:this指针存在栈区。因为this指针属于形参。vs可能会优化,把this指针放到寄存器中。