🚀类
✈️类的介绍
在C语言中,结构体中仅能声明变量并不能定义函数,不过在C++中结构体进行了扩展,不仅能声明变量也能定义函数,类似于C++中的类
在C++中定义一个类,可以使用struct
或者class
关键字定义,并且类的成员函数生命和定义可以分离:
struct a {
int x; //声明的变量,被称为成员变量
void test(){} //定义的函数,被称为成员函数
};
class a {
int x; //声明的变量,被称为成员变量
void test(){} //定义的函数,被称为成员函数
};
//成员函数test(),声明和定义分离
class a {
int x;
void test();//声明
}
void a::test(){}//定义
a x;//类定义的变量称为对象
上述两种方式定义类都可以,两者的区别在于struct
的成员默认是public
(公有的),而class
默认是private
(私有的)。
✈️类的访问限定符
在C++中,类的访问限定符用于控制外部代码对类的成员的访问权限。
C++提供了public
、private
和protected
这三种访问限定符。
- 公有访问(
public
):使用public
关键字指定的公有成员,在任何地方都可以访问,包括外部代码和其他类,在整个程序中可见。 - 私有访问(
private
):使用private
关键字指定的私有成员,只在类的内部可以访问,其他代码无法直接访问包括子类。 - 受保护访问(
protected
):使用protected
关键字指定的受保护的成员,只在类及其子类中可以访问,其他代码无法直接访问。
✈️类的封装
基于类的访问限定符,使得类的数据以及方法的实现得以隐藏,仅提供接口函数与外界进行交互。
封装的好处:
- 数据保护:封装隐藏了类内部的实现细节,外界无法随意的修改破坏类的内部状态
- 简化接口:外界只需要与类的接口交互,降低了系统的复杂性,代码更易维护
- 更易调试:问题发生时,通常集中在类的内部,而不会分散在整个代码中
🚀面向对象编程
众所周知,C语言是一门面向过程的语言,而C++在C语言的基础上扩充了面向对象的特性,使得C++既可以进行面向过程,也可以进行面向对象的编程,二者兼得。
如果我们要写一个五子棋的游戏,这两种变成方式会有什么不同
面向过程编程:
1 创建一个二维数组作为棋盘
2 写一个棋盘的初始化函数
3 写一个打印棋盘的函数
4 写一个读入玩家输入并操作盘的函数
5 写一个判断输赢的函数
6 main函数写一个循环调用上述函数实现游戏逻辑
面向对象编程:
1 定义一个棋盘类
成员变量:一个二维数组表示棋盘
成员函数:提供棋盘的初始化、打印、下棋更新以及判断胜利的接口函数
2 定义一个玩家类
成员变量:一个字符(表示不同的玩家)
成员函数:提供玩家下棋输入的接口函数
3 定义一个游戏类
成员变量:两个玩家对象、一个棋盘对象以及一个玩家类指针(用于轮流下棋)
成员函数:提供游戏开始、游戏进行、游戏检查、玩家切换的接口函数
4 main函数中创建一个游戏类的对象,然后调用游戏开始的接口
上面两种编程方式,很明显面向过程数据与对数据的操作也就是函数是分离的,而面向对象数据与函数是相统一的,这样更有利于维护代码并且之后对于游戏进行拓展也更为容易。
🚀类与对象的联系
类创建对象的过程称为实例化,类本身并不会被分配空间,只有类实例化出来的对象会占据空间。
简单理解,类是类型,对象是创建出来的变量,变量才会被分配空间。
那么类实例化出来的对象会占据多大空间,怎么计算呢?
先说结论:对象与结构体变量一样大小为成员变量之和,不过要遵循内存对齐原则,并不会为成员函数开辟空间
class A{
int x;
char b;
void test(){}
};
cout << sizeof A << endl;
下图是上述代码在VS2022
中运行的结果:
根据内存对齐的规则,x
和b
变量只需要5
个字节的空间,然后空间为4
的整数倍,所以是8
。
可见这里面并没有为成员函数开辟空间,实际上成员函数在编译期间生成,并在公共代码段中,只存在一份,共所有的对象调用。
🚀this指针
✈️引出this指针
首先我们先定义一个类:
class A{
public:
int x;
int y;
void init(int a,int b){ // 初始化类
x = a;
y = b;
}
};
int main(){
A a,b;
a.init(1,2);
b.init(3,4);
cout << a.x << " " << a.y << endl;
cout << b.x << " " << b.y << endl;
}
输出:
1 2
3 4
为什么会输出上面的结果呢,在前面我们知道成员函数只有一份,但是上面a.init()
以及b.init()
这两个对象调用init()
他是如何区分到底是给a
还是给b
初始化的呢?
实际上,c++编译器会给每一个非静态成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成,而这个指针就是this
指针
上述类A
中的init()
函数实际上是下面这个样的
void init(A* const this, int a, int b){
this->x = a;
this->y = b;
}
✈️this指针的特性
-
this
指针不能在成员函数参数列表中显示写出来(规定) -
this
指针不能修改,它的类型是类 * const
-
this
指针可以在成员函数钟显示调用如下:
//这么写和上面的写法都行, class A{ public: int x; int y; void init(int a,int b){ // 初始化类 this->x = a; this->y = b; } };
-
this
指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx
寄存器自动传递,不需要用户传递
好了,就分享到这,如果有帮到您,就帮我点个赞呗,感谢大家支持!!!