🌈 个人主页:白子寰
🔥 分类专栏:C++打怪之路,python从入门到精通,数据结构,C语言,C语言题集 👈 希望得到您的订阅和支持~
💡 坚持创作博文(平均质量分82+),分享更多关于深度学习、C/C++,python领域的优质内容!(希望得到您的关注~)
目录
面向对象和面向过程的认识
C语言是面向过程 的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
而C++是基于面向对象 的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
那什么是过程?什么是对象呢?
我们在生活中举例子:比如我要去烧一壶开水
对象:我,热水壶,水,排插/插座,热水壶托盘
过程:把水接到水壶里 --> 关闭水壶盖 --> 把热水壶放到托盘中 --> 连接好插排/插座 --> 按下热水壶开关 --> 静等几分钟 -->一壶水烧开了
类
类的引入(以下以Stack为例)
在C语言中,我们学过结构体,但在C语言的结构体当中,只能由成员变量组成,回顾一下怎么用C语言实现(Stack)栈的呢?
然而在C++ 当中,结构体里不仅可以定义成员变量,还可以定义成员函数,那就是"类"
类的介绍
在C++当中,喜欢把struct写成class(类),什么是类?
cpp
class ClassName
{
//由 成员变量 和 成员函数 来组成
};
注:1、class和struct相似, 2、ClassName是类的名称,
3、名称后需跟中括号{},4、右中括号后还有分号 ( ; )
那么在C++当中关于栈的类是怎么定义的呢?
类的第一种定义方法
在class(类)中声明和定义成员变量和成员函数(可以在class中具体实现成员函数)
注:(成员函数如果放在类体中,编译器可能会当成内联函数处理)
(关于访问权限我们在后续中会讲到,这里先做铺垫)
类的第二种定义方法:类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。
在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
在class(类)中定义成员变量和定义成员函数,
在.cpp文件中声明成员函数 (也就是通过类和作用域限定符指定实现Stack类中的某个函数)
成员变量命名规则
建议①
成员变量用**_year** 表示
建议②
成员变量用 前缀(m_year) 或者 **后缀(例如:year_m)**来表示
类的访问限定符
访问限定符的介绍
C++实现封装(文章下面会讲到)的方式:
用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
访问限定符包括:public(公有),protected(保护),private(私有)
注: 1、public修饰的成员在类外是直接可以访问的
2、private修饰的成员在类外不能直接被访问(protect和private是类似的)
3、访问权限作用域从访问权限开始到下一个访问权限出现结束
4、 如访问没有限定符,那就到 } 结束
5、class默认访问权限是private,struct默认访问权限是public(struct兼容C语言)
封装
面向对象的三大特性:封装、继承、多态。
在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来 和对象进行交互。
封装本质上是一种管理,让用户更方便使用类
就像上面说的 面向对象和面向过程的认识 一样
烧一壶开水,我们只需关心把水装进水壶,再按下按钮就可以了
并不关心开水是怎么烧开的,它的内部用什么装置和线路组成的(封装)
用户 只需要与厂家提供的按钮,热水壶等显而易见直接实现的外部装置之间进行交互
在C++语言中实现封装,
可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
类的实例化
概念
用类类型创建对象的过程,称为类的实例化
类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,
定义出一个类并没有分配实际的内存空间来存储它
打个比方:
类实例化出对象就像现实中使用建筑设计图建造出房子,
类就像是设计图 ,只设计出需要什么东西,但是并没有实体的建筑存在,
同样类也只是一个设计 ,实例化出的对象才能实际存储数据,占用物理空间
类 和 对象 是 一对多的关系
一个类可以有多个对象,比方类是设计图,对象是通过设计建出来的房子,
一个设计图可以设计建造出多个类似的房子
理解类的实例化(含图片和代码)
举例:Data日期类
cpp
class Data
{
public:
void Init(int yaer, int month, int day)
{
m_year = yaer;
m_month = month;
m_day = day;
}
private:
int m_year; //年
int m_month;//月
int m_day; //日
};
int main()
{
Data s1; //定义(实例化)对象
Data s2; //定义(实例化)对象
s1.Init(2024, 4, 25);
s1.Init(2024, 4, 25);
Data s3; //定义(实例化)对象
Data s4; //定义(实例化)对象
s1._yaer++; //成员变量的权限为private
s2._yaer++;
return 0;
}
类对象模型
计算类对象大小
(看下面Data类,类A、B、C)
cpp
class Data
{
public:
void Init(int yaer, int month, int day)
{
_year = yaer;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
class A
{};
class B
{
private:
int a;
char b;
};
class C
{
public:
void D(){}
};
int main()
{
Data d1;
cout << sizeof(d1) << endl;
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
}
怎么计算类对象的大小呢?(Data类,类A、B、C)它们的大小分别为多少?
一个类的大小,实际就是该类中"成员变量"之和,
当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
控制台输出显示
结构体内存对齐
详细讲解请看该篇文章:结构体超详细总结(含结构体内存对齐)http://t.csdnimg.cn/YIAAr
this指针
this指针的引入
看一下前面提到的Data(日期类)
cpp
class Data
{
public:
void Init(int yaer, int month, int day)
{
_year = yaer;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;
Data d2;
d1.Init(2024, 4, 27);
d2.Init(2023, 4, 27);
d1.Print();
d2.Print();
return 0;
}
现有这样一个问题,
当d1调用Init成员函数时,该函数如何知道应该设置d1对象而不是设置d2对象呢?
C++中通过引入this指针解决该问题,
即:C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),
在函数体中所有"成员变量"的操作,都是通过该指针去访问。
只不过所有的操作对用户是透明 的,即用户不需要来传递,编译器自动完成。
this指针的特性
1、this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2、 只能在**"成员函数"的内部使用**
3、this指针 本质上是"成员函数"的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4、this指针是"成员函数"第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递,不需要用户传递
d1和d2都调用该成员函数,但结果却不同的原因是:
void Print() 函数再编译器编译是 void Print(Data* const this),有一个隐藏参数this指针
d1调用函数时,是这样子来访问的:
&d1->_year、&d1->_month、&d1->_day,
此时this指针就是d1的指针,&d1是实参,Data* this是形参(局部变量),访问的是d1的对象_year,_monh,_day
C语言和C++实现Stack的对比
C语言
共性
1、每个函数的第一个参数都是Stack*
2、函数中必须要对第一个参数检测,因为该参数可能会为NULL函数中都是通过Stack*参数操作栈的
3、调用时必须传递Stack结构体变量的地址
结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。
C++
C++中通过类 可以将数据 以及 操作数据的方法进行完美结合,
通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。
而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原,
即C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护。
***********************************************************分割线*****************************************************************************
完结!!!
感谢浏览和阅读。等等等等一下,分享最近喜欢的一句话:
"欲买桂花同载酒,终不似,少年游"。
我是白子寰,如果你喜欢我的作品,不妨你留个点赞+关注让我知道你曾来过。
你的点赞和关注是我持续写作的动力!!!好了划走吧。