作者主页: 作者主页
本篇博客专栏:C++
创作时间 :2024年6月21日
一、类与对象的初步认识
1、类其实就是对对象的抽象,而对象就是对类的具体实例
类不占用内存,而对象占用内存。
2、面向对象与面向过程
C语言是面向过程的,关注的是过程中的数据与方法。
C++是面向对象的,关注的是对象’的属性与功能。
在C语言中不能再结构体中包含函数,但是在C++中却可以。
struct student
{
char _name[20];
int _age;
void SetStudentInfo(const char *name, int age)
{
strcpy(_name, name);
_age = age;
}
};
其实这里的结构体就是类,C++中兼容C语言中结构体用法,同时增加了类的用法
其实和C语言最大的区别就在于: C语言中struct只可以定义变量,C++中的struct既可以定义变量,也可以定义函数(实现方法)。
二、类的定义
其实在我们实际的开发中呢,我们不会去使用struct去定义类,而是使用class,下面我们来看一下它的用法。
class className
{
//类体:由成员函数和成员变量组成
}; //一定要注意后面的分号
这里的class就是定义类的关键字,classname就是这个类的名字。
注意:类的成员函数默认是内联(即是内联函数)的。
类的两种定义方式:
1、类和声明都放在类体中:
class Person
{
public:
//显示基本信息
void showInfo()
{
cout << _name << "-" << _age << endl;
}
public:
char* _name;
int _age;
};
2、类的声明放在.h文件中,类放在.cpp中
声明放在类的头文件person.h中
class Person
{
public:
//显示基本信息
void showInfo();
public:
char* _name;
int _age;
};
三、类的访问限定符及封装
C++的三大特性就是:封装、继承、多态,我们在这里先只说一下这个封装。
要想了解封装,首先我们要知道它的概念:将数据和操作数据进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。我相信大家看到这里也是一脸懵,我给大家举个例子:博物馆是如何管理的呢?如果不采取措施,文物将被损坏。所以我们就建立了一个博物馆,把文物都封装起来,不让人们看。但是我们开放了购票机制,可以买票突破封装进去参观。这就和类一样,我们使用类数据和方法都封装到一下。不想给别人看到的,我们使用protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访问。所以封装本质是一种管理。
这里我们就要提到三个访问限定符:
访问限定符说明:
- public:public是公有操作符,听他的名字就知道,都可以去访问,所以public修饰的成员可以在类外直接访问。
- protected和private修饰的不可以在类外直接被访问(此处的两者作用相同)
- 访问权限是从改访问限定符出现到下一个访问限定符出现为止
- 在class中,默认的访问权限是private,struct中是public,这也是这两者的区别
注意访问限定符只在编译时有用,当数据映射到内存后,没有任何限定符之间的区别。
四、类的实例化
用类类型创建对象的过程,称为类的实例化
- 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
四、类的大小
一个类中既包含了成员函数,又包含了成员变量,那么一个类的实例化对象中包含了什么?怎么计算一个类的大小?
只保存成员变量,成员函数存放在公共的代码段,通过指针的方式来找到成员函数。当然这里也遵循内存对齐原则。
class A1 {//占四个字节
public:
void f1() {}
private:
int _a;
};
// 类中仅有成员函数
class A2 {//占一个字节
public:
void f2() {}
};
class A3
{};
空类的大小:空类占1个字节,占位用,告诉系统我这里定义了一个类,虽然它是空的。
结论:一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
不清楚内存对齐原则的,可以去看一下这篇文章:内存对齐原则
五、this指针
首先我们看一下这串代码:
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.SetDate(2022, 5, 11);
d2.SetDate(2022, 5, 12);
d1.Display();
d2.Display();
return 0;
}
运行之后结果是这样的:
我们可以通过汇编来看一下:
我们可以发现,最终打印的时候调用的Display()是同一个函数, 那么既然d1,d2调用的都是同一个函数,编译器如何知道d1是2022-5-11,d2是2022-5-12呢?Display()都访问的_year,_month,_day。而且去公共代码区访问的Display(),这是为什么呢?
这是因为C++在这段代码中做出手脚,C++在这里增加了一个this指针,这里是因为Display会增加一个this形参。C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
在调用的时候也传的是各自的地址。这样就十分清晰明了了。这就是隐含的this指针
在实际中,this指针是被const修饰的,指针本身不能被修改,但是内容可以被修改
this指针的特性总结:
1. this指针的类型:类类型* const。
2. 只能在“成员函数”的内部使用。
3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
最后:
十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:
1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。
2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。
3.成年人的世界,只筛选,不教育。
4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。
5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。
最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)
愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!