个人主页:点我进入主页
专栏分类:C语言初阶 C语言进阶 数据结构初阶 Linux C++初阶
欢迎大家点赞,评论,收藏。
一起努力,一起奔赴大厂
目录
一.前言
二.类的定义和使用
2.1类的引入
2.2类的定义和访问限定符
2.21定义
2.2.2访问限定符
2.2.3代码示例以及对上面的分析
2.2.4封装
2.3类的内存对齐
2.3.1类中的函数的位置
2.3.2小问题
2.3.3内存对齐
2.3.4内存对齐意义
在前面我们写过C++入门中的函数重载,命名空间,缺省参数,引用,还有一些新的语法, 这些内容是我们学习后面的基础,在今天我主要给大家带来关于类的内容,其中包括类的定义和使用,访问限定符封装,类的实例化,计算类的大小以及内存对齐。
在c语言期间我们的结构体你还记得吗?在C++中祖师爷对它进行了升级,升级成了我们的类,我们写一个代码表示C语言中的结构体:
struct A {
int num1;
int num2;
int* p;
};
我们定义变量时使用:
struct A a;
如果我们想定义一个函数,我们需要在结构体外进行声明和定义。
那我们在C++中是如何使用结构体呢?我们看下面的代码
struct Data {
int _year;
int _month;
int _day;
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
};
int main()
{
Data d1;
d1.Init(2024, 1, 31);
return 0;
}
在C++中我们更喜欢使用class来定义。
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。(也就是说我们将class代替我们的struct,当然struct也可以,{}中包含的分为两部分一是成员变量,一部分是成员函数)。
访问限定符包括3个分别是public(公开),private(私有),protected(保护),其中public可以任意访问,protected和private不能任意访问只能在类里面访问,访问权限是从第一个访问限定符到下一个访问限定符之间,struct默认为public,class默认为private。
#include
using namespace std;
class Data {
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()
{
Data d1;
d1.Init(2024, 2, 1);
d1.Print();
return 0;
}
我们采用class的形式,我们的第一个限定词是public第二个限定词是private,其中public的作用域是public到private,private的作用域是从private到结尾。在main函数中我们定义的d1可以称为我们的对象,我们访问public作用域的内容时我们直接利用对象去访问,下面的访问方式是不对的:
Init(2024, 2, 1);
Data::Init(2024, 2, 1);
这两种都存在存在问题,都是不正确的,对于public作用域的我们可以在类的里面和外面进行访问 ,那对于private或protect作用域的内容呢?我们看到在定义Init函数时我们在类里面就使用了我们private的内容,因此在类里面可以访问,那类外面呢?我们看下面
d1._year = 1;
Data::_year;
这两种都是会报错的
所以我们可以看到private作用域的变量或函数只能在类里面进行访问,不能在类外访问,由于private和protect在这里一样,所以不做过多演示。
我们可以将封装看成一种管控,c++将变量和方法放在类里面,允许让我们访问的使用public进行修饰,不想让我们访问的使用private或protected进行修饰。
我们需要知道,类中函数的位置,类中函数和成员变量是放在不同的位置,
如果我们定义一个指针
Data d1;
Data* p = &d1;
我们需要知道p指向成员变量。
我们看下面的代码输出结果是什么:
#include
using namespace std;
class Data {
public:
void Print()
{
cout << "Print()" << endl;
}
};
int main()
{
Data d1;
Data* p = &d1;
p->Print();
return 0;
}
很显然我们的结果是Print();
那我们的这行代码输出结果是什么呢?
Data* p = nullptr;
p->Print();
是不是很多人说对空指针的解引用,会导致空指针的解引用,其实这样的结果还是Print(),为什么呢?我们看上面类的成员变量和成员函数是分开的,我们的p是指向我们的成员变量的区域,无论成员变量是什么样子,我们的函数区域是不变的。
Data* p = nullptr;
(*p).Print();
我们这个代码个上面的一样,都会正常运行。
类的内存对齐和我们在前面c语言中的内存对齐一样,在vs中我们的对齐数为8,我们的Data中_year占0,1,2,3的位置,_month占4,5,6,7,。_day占8,9,10,11占12个12是4的倍数所以占12个,在这里不做具体解释,不理解的可以在内存对齐中查看。
我们知道了内存对齐,那它有什莫意义呢?我们这样舍弃空间是为什么呢?我们需要知道一些机器一次只能访问4个或8个字节,我们以4个字节为例,
如果我们一次访问4个字节,第一种没有对齐的int需要访问两次,第一期是前三个字节,第二次要访问第4个字节,而第2种我们能访问int能直接进行访问,这样可以减少我们的访问次数,我们采用内存对齐是一种空间换时间的方式,这就是内存对齐的意义。
this指针是默认生成的,类型为*const 我们不能在形参和实参的位置显示写,但函数种可以用,这是this指针的定义,我们看一看相关代码
#include
using namespace std;
class A {
public:
A(int a = 1)
{
_a = a;
}
void Print(A*const this)
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A a;
a.Print(this);
return 0;
}
我们的代码就会报错,错误如下:
如果我们将Print函数中加上this呢?
void Print()
{
cout < _a << endl;
}
程序就会正常运行。
今天的内容就结束了,这些都是类的基础,大家可以认真看看,对于后面的内容非常重要。最后希望大家可以一键三连。