c++中相对于c语言最大的创新就是类的出现,那么类究竟是怎么一回事呢?
今天好好了解一下吧;
目录
什么是面向对象
我们都知道,c++是面向对象的语言,而c语言是面向过程的语言;
那么什么是面向对象;
什么是面向过程呢?
面向对象的语言
所谓面向对象的语言就是将一个系统中需要用到的东西,全部抽象为一个个对象;
然后靠对象的交互完成系统;
是一种 “自下而上” 的编程语言,也就是先设计好底层组件,然后组装起来;
而面向对象的这种形式就造就了面向对象语言的特点:
封装性,多态性,继承性;
面向过程的语言
而面向过程则是先定好一个系统的框架,然后再在里面添砖加瓦;
也就是在源文件内部添加好一个个函数(方法);
这里的不同,导致两种类型语言使用场景不同;
类
c++中最重要的莫过于类这一改进,也是导致c++是面向对象的最重要的原因;
因此想要学好c++,学好类是必不可少的;
事不宜迟,我们就来学习类吧~
类的定义
class (classname)
{
// 变量成员或者方法;
};
类的定义需要有 class 关键字,定义好名字后再在里面定义成员或者方法;
结构体和类的定义很类似,但是类却可以定义方法;
而类定义方法就是c++对于结构体最大的改进;
那么我们就实际上感受类的作用吧;
#include<iostream>
using namespace std;
class Date {
private :
int _year;
int _month;
int _day;
public:
void Init(int year = 2022, int month = 10, int day = 4)
{
_year = year;
_month = month;
_day = day;
}
void Read()
{
cout << "year = " << _year << endl;
cout << "month = " << _month << endl;
cout << "day = " << _day << endl;
}
};
int main()
{
Date a;
a.Init();
a.Read();
return 0;
}
当然,类和结构体一样,能够将函数的声明与定义放在不同的位置;
若是将类的函数声明和定义放在一起,那么这个函数相当于内联函数;
//Date.h中
#include<iostream>
class Date {
private:
int _year;
int _month;
int _day;
public:
void Read();
void Init(int year = 2022,int month = 10,int day = 4);
};
//Date.cpp
#include"Date.h"
using namespace std;
void Date::Init(int year = 2022, int month = 10, int day = 4)
{
_year = year;
_month = month;
_day = day;
}
void Date::Read()
{
cout << "year = " << _year << endl;
cout << "month = " << _month << endl;
cout << "day = " << _day << endl;
}
我们可以看到,这个类中不仅有成员变量,还有各种方法;
还有这种没有了解过的关键字:private,pubulic;
接下来我们就慢慢了解吧;
(顺带一提,类的成员变量在哪里都能用,只要是在类的内部就行了)
类的关键字(访问限定符)
之前的类里面出现了两种访问限定符;
而类一共有以下三种访问限定符;
private(私有)
public(公有)
protect(保护)
那么访问限定符究竟有什么用呢?
又有什么区别呢?我们来看看;
访问限定符的作用:
1. public 修饰的变量或者方法可以在类外直接访问;
2. private 和 public 修饰的变量或者方法只能在类内部访问;
3. 访问限定符的作用域一直持续到下一个访问限定符;
4. 若是后面没有别的访问限定符,则作用域在 } 处结束;
5. class 中默认的权限是 private;//struct 也有默认权限,不过是public
看完访问限定符的作用和 class 的默认权限后,我们可以知道访问限定符有多重要了;
不过为什么需要创建这三个访问限定符呢?
这不是导致使用类的时候还需要注意这个限定符吗?
实际上这就涉及到面向对象的语言的封装性的特点了;
我们用好了访问限定符,就能选择哪些接口能够供给用户使用,哪些需要隐藏;
这就能够更方便用户的使用,也能隐藏好内部的细节;
类的作用域
之前将类的定义和声明分离的时候,就已经演示过在类的外面定义类的成员了;
这里类的作用域实际上就和普通定义结构体一样,只是需要用 :: 来声明罢了;
这一点和命名空间很类似,但是类和命名空间还是有不同的;
那么类和命名空间有什么不同呢?
类和命名空间的不同
我们首先需要明白一点,命名空间内部的变量都是可以直接用的;
但是类内部的变量却不行;
这就涉及到类的实例化了;
类的实例化:用类类型创建一个对象,就是类的实例化;
当类没有定义一个对象的时候,类就并没有占用实际的空间;
类内部变量也没有占用实际空间,这点和结构体类似;
而只有用类创建了一个对象,该对象才会在内存空间内开辟一个空间;
不过一个类对象在内存空间实际上会占多少内存呢?这又是一个需要探讨的点;
类的内存计算
之前说过,类是结构体的改进,那么类的内存计算和结构体的内存计算应该类似;
但是,类和结构体不一样的是,类内部可以定义方法的,那么类内部的方法会不会影响类的大小?
class Date {
private:
int year;
int month;
int day;
public:
void Init(int _year = 2022, int _month = 10, int _day = 5)
{
//.......
}
void Read()
{
//....
}
};
我们敲上这样一段代码,按照结构体的方法,我们先忽略 Init 和 Read 两个函数;
那么单纯计算三个变量,那么该类应该是12个字节的大小;
那么两个函数该怎么办呢?是将两个函数看作函数指针,还是怎么做?
我们直接看结果:
我们能够看到,实际上这个类的大小就是12个字节;
那么这两个函数怎么办呢?难不成这两个函数实际上是没有占空间的吗?
实际上,c++的创始人想到了一个绝佳的方法;
将类里面的方法都放在一块内存区域中,只给成员变量开辟不同的区域;
此外,类的内存大小计算,内存对齐之类的,全部和结构体是一样的;
不过有一个例外,那就是空类;
我们将类的成员全部屏蔽掉,可以看到即使是空类,也会有一个字节的空间;
用来标识这是空类;
明白了类的方法如何计算之后,我们再来看看结构体内存对齐规则;
这个规则可以直接用于类的内存计算;
结构体的内存对齐规则:
1. 第一个成员在与结构体偏移量为 0 的地址处。2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS 中默认的对齐数为 83. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
拿刚刚的类来说明:就是这样
从偏移量为0开始,按照规则开始计算,可以得出最终字节大小为12;
在了解类的内存计算后,又来了一个新的问题;
既然类的方法都是在同一个空间内部,那么编译器怎么知道方法中的变量,是哪个对象的变量呢?
这就是this指针出场时候了;
this指针
我们先来看看用类类型创建两个对象,用方法初始化,能不能成功;
class Date {
private:
int _year;
int _month;
int _day;
public:
void Init(int year = 2022, int month = 10, int day = 5)
{
_year = year;
_month = month;
_day = day;
}
void Read()
{
cout << "year = " << _year << endl;
cout << "month = " << _month << endl;
cout << "day = " << _day << endl;
}
};
int main()
{
Date d1, d2;
d1.Init(2022, 10, 6);
d2.Init(2023, 10, 6);
d1.Read();
d2.Read();
return 0;
}
可以看到确实成功了;
这就是this指针的用处了;
同学们这个时候就会很疑惑;
明明方法内部没有this指针啊?
为什么能够辨别不同的对象?
实际上this是一个隐藏的指针,会指向当前对象;
函数内部所有成员变量的操作都是通过this指针进行的;
只是this指针是隐藏的,用户可以不用理会,当然,我们也可以加上this指针;
就像这样,也是可以的;
而由于平时我们的this都是隐藏的;
那么我们像使用 Init 这类成员变量和形参相同的函数时;
最好给成员变量前面加上" _ " 这种特殊符号,用以区别,否则编译器可能会混乱;
不过知道了编译器如何区别不同的对象之后,还有一个问题;
那就是this指针究竟是存在哪里的?
而this指针的特性是什么呢?
这里直接介绍一下;
this指针的特性
1. this 指针的类型:类类型 * const ,即成员函数中,不能给 this 指针赋值。2. 只能在 “ 成员函数 ” 的内部使用3. this 指针本质上是 “ 成员函数 ” 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给this 形参。所以 对象中不存储 this 指针 。4. this 指针是 “ 成员函数 ” 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传递,不需要用户传递
就像上面的Date类,this指针的类型是 Date * const;
总结
类作为c++最大的一个改进,其地位在c++中是十分高的;
而这里只是介绍了类的定义,内存计算以及this指针这几个部分的知识;
而类的内容远远不止如此;