前言
C语言大家都不陌生,它的最大特点是面向过程
而C++是C语言的升级版,它由原来的面向过程转变为面向对象
两者有什么区别呢?
本次文章带你处认识C++中的面向对象
面向对象和面向过程
C语言面向过程
- 面向过程就是关心各个步骤的交互,步骤的顺序影响结果
C++面向对象
- 面向对象就是关心各个对象之间的交互,对象之间的如何交互影响结果
简单的定义,无法理解二者的区别,谁优谁劣
举个例子——洗衣服
如果是面向过程,我们将会注重过程,步骤的顺序
则洗衣服变成:
面向过程就是步骤之间交互,一个步骤接着一个步骤,一个步骤对另一个步骤产生影响
如果是面向对象,我们就会注重对象之间如何合作,关注对象做什么
则洗衣服变成:
面向对象就是对象之间交互,一个对象对另一个对象做事
这样一看,区别就出来了
- 面向对象,比面向过程简单太多了
面向对象的本质也是面向过程,只是面向对象将面向过程中的步骤隐藏进了对象中,将具体步骤隐藏,不暴露出来
步骤实际并未减少,但减少了办事人的工作量
- 如果是面向过程:我们需要“洗”、“换”、“搓”、“放”
- 如果是面向过程:我们只需要“放”
类
C++面向对象的特性因为类得以体现
类是C++相较于C语言一种新的形式
class ClassName//class+类名
{
//具体内容
};//分号一定要加!
一个类在投入使用前,有三个阶段
- 类的声明:表示有这个类
- 类的定义:表示这个类中有什么
- 类的实例化:创建一个类对象
类的定义
我们通常将类的声明和定义放在一起,其中也有一些特殊情况,需要在定义前先声明
声明形式
class ClassName;//直接class+类名,注意分号
我们重点看类的定义
类的定义
- 对类进行充实,添加成员,如函数和变量
其中
- 类的函数,我们称之为成员函数或者类的方法
- 类的变量,我们称之为成员变量或者类的属性
class ClassName
{
//函数
//方法
};
C++是C语言的升级,C++的类不仅可以有属性,还可以有函数,而结构体只能有属性。
类的两种定义方法
- 声明和定义全部放在类体中,注意:成员函数如果在类中被定义,有可能被编译器当成内联函数
- 声明放在类体中,定义放在类外,定义在类外时,成员函数前添加——类名::
- 如:我们一般将类放在.hpp中进行声明,类的成员函数和属性也在类中声明,但成员函数的定义放在.cpp中进行定义
我们一般建议采用第二种定义方法,这就和手机商卖手机一样
- 卖是靠手机专卖店卖
- 造是靠手机工厂造
你永远无法看到一个手机是如何生产的,交到你手上就是一个完整的手机
一定程度上增加了保密性,更加安全
我们实际采用第二种方法,不仅更加安全,也能让代码不冗余
类的实例化
类的声明和定义完成后,就可以直接使用了吗?
试一下
报错了,为什么?
因为没有实例化!
类没有实例化之前,都是虚的。
- 就像函数没有调用之前,充其量只是一传存储在文件中的文本信息,没有任何作用
就像小说中说的
传说中的某某宝物,我曾经旨在一本记载上古宝物的书籍中见过,据说有XX功效
相当于,类只有声明和定义,没有实例化
没有想到,今天居然在这里见到了
类被实例化了
类没有被实例化之前,几乎没有用,形如虚设
注意关键字“几乎”
- 类的方法不一定不能用
- 类的属性一定不能用
类,只是一个类型,它需要一个载体来实现它的功能
就像《凡人修仙传》中的没有躯体的修士灵魂
几乎无法做任何事情,但他仍有思想,有记忆,能思考,自己知道能做什么,要做什么
但只有等夺舍,重新拥有躯体,才能真正做事
如果强行使用未实例化的类中的成员,则会引发报错。
实例化后,就可以使用类
实例化类,相当于创建一个变量,我们习惯将类的变量称之为对象
通过对象,来使用类中的成员变量和成员函数
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> class A { public: void Print() { std::cout << "a: " << a <<" " << "b: " << b << std::endl; } int a; int b; }; int main() { A tmp;//实例化一个类A对象tmp tmp.a = 10;//使用属性 tmp.b = 20;//使用属性 tmp.Print();//使用方法 return 0; }
运行结果
类的大小
类中有属性有方法,那么类的大小是多少呢?
验证一下
class A { public: void Print() { std::cout << "a: " << a << " " << "b: " << b << " " << "c: " << std::endl; } private: int a; int b; int c; }; int main() { A tmp; std::cout << sizeof(A) << std::endl; std::cout << sizeof(tmp) << std::endl; return 0; }
结果
为什么会这样?
类的大小只和类的属性有关,与类的方法无关
当你使用一个类创建多个对象的时候,每个类对象的属性的值会有所不同,但每个类对象使用的方法执行的功能都是一样的。
我们有必要为了一个一样的函数单独开辟空间吗?
没有必要
类就像小区中的一种户型设计图,这种户型只有一个
但小区根据户型建造的每一套房子就像由类实例化的对象,可以有很多个
它们有着相同的布局,就像类对象有相同的方法和属性
类的属性就像每套房子中的厨房客厅卧室,也是独立的,可以自己设计装修风格
而类的方法,就像是小区的公共场所,如篮球场、公园
大家用这些公共场所的目的是一样的,完全没有必要每一个人一个篮球场,每个人一个公园
类被实例化后
- 它的变量会根据初始化方式不同,存储在不同区域
- 类的方法,则会统一存放在一个公共代码区,等待调用
this指针
当类对象使用类方法,类方法中涉及对类的属性相关操作的时候,是不是会出现歧义
什么歧义?
当用一个类创建两个对象A和B
该类具备属性,并且有一个类方法Print打印类的属性的值
当对象A和对象B同时调用Print方法的时候
打印出的属性,是对象A的属性,还是对象B的属性?
实际上,我们知道
- 对象A调用,就打印对象A的属性的值
- 对象B调用,就打印对象B的属性的值
但为什么?
为什么不同对象使用相同类方法的结果不一样?
因为每一个类的方法的参数中,会有一个指针this
这个this指针,指向当前类的一个对象,类型为——类名*
当方法被定义的时候
- 我们定义的是:返回值类型 方法名(参数1 , 参数2,......)
- 编译器看到的是:返回值类型 方法名(this指针,参数1,参数2,......)
当方法中,涉及对类的属性操作
- 我们看到的是:属性
- 编译器看到的是:this->属性
当方法被类对象调用的时候,类对象就会把自己的地址,传递给这个指针。
类方法,就可以通过指针的值,来找到对应的类对象
这样,同样的类方法,因为this指针的值不同,就可以访问不同的类对象
不懂的,可以看下面这个例子
你在学校是一个学生类对象,你们学校会有很多学生对象
学生都会有一张自己的校园卡,校园卡上有学生自己的属性,如余额
当你们在学校用餐的时候,是用机器刷卡扣钱的
机器,相当于一个类方法,大家都可以使用
当你用机器刷卡的时候
刷自己的卡,会扣别人的钱吗?
并不会,只会扣自己的钱,因为你使用校园卡进行刷卡的时候
机器会找到你的信息,然后从你的余额上扣钱
校园卡刷卡的过程,相当于传递地址
告诉机器“你应该去找哪个类对象”,“你应该扣谁的钱!”
两个this指针问题
- 问题一:this指针可以为空吗?
- 问题二:this指针存在哪里?
解决这两个问题前,首先得认清this指针的本质,靠本质去解决问题
this指针的本质:不过是一个函数的一个形参罢了
this指针可以为空吗?
this指针是一个函数的形参
这个形参的类型是指针,指针当然可以为空!
所以,this指针可以为空,并且函数依然可以正常被调用
验证一下
class A { public: void Test() { std::cout << "测试一下" << std::endl; } }; int main() { A*tmp=nullptr; tmp->Test(); return 0; }
运行结果
this指针存在哪里?
铭记this指针的本质——一个函数的一个形参罢了
当一个函数执行前,它所需要的空间大小,已经在栈帧中开辟好了
函数存于栈帧之中,其中的形参也是
所以,this指针存在于函数栈帧之中
封装
我们在之前就说过,面向对象本质上就是面向过程,但面向对象将过程中的步骤隐藏进了对象中
这种隐藏的方法,我们称之为“封装”
- 封装在于将复杂的步骤进行隐藏,只放在内部,外部是无法看见的,只提供给外部一个接口
当外部使用接口的时候,步骤就会开始!
封装是C++的三大特性之一,它的存在,让C++显得更加简单,易用。
怎么说呢,举个例子
我们平常使用的电脑,它工作的时候,内部硬件会进行十分复杂的交互。
计算机厂商在电脑出厂的时候,在外部套上一个壳子,将内部实现细节全部隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等。
我们看到的,只有关机键、鼠标、键盘等,我们也只需要使用这些,就可以享受电脑的全部功能,我们需要了解内部硬件是怎么交互的吗?
如CPU怎么工作、硬盘怎么存储数据
显然不用,因为我们有封装,不需要了解内部硬件怎么工作,互相怎么合作
我们只需要提供给我们的简单接口——鼠标、键盘等就可以了
访问限定符
我们用封装,对过程进行隐藏
我们不希望把复杂的东西暴露在外面,另外一些隐私的东西,或者容易引发错误的东西,我们也不想暴露,被他人随意访问,如:类的属性
因此,我们用三个访问限定符来对类的成员进行选择性隐藏和公开
三个访问限定符
- protected
- private
- public
访问限定符说明
- public修饰的成员在类外可以被直接访问
- protected和private修饰的成员在类外不能被直接访问
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域到类结束
因为我们的诉求,是对一些成员进行选择性隐藏和开放,增强保密性
所以需要我们主动去设置访问限定符,但我们也有忘记的时候
这时候,编译器就会将没有主动被限定的部分,用默认访问限定符进行限定
C++类的默认访问限定符是private
C++中的结构体和类
C++是在原来C语言的基础上进行升级,它不仅有更多的新玩法,也保留了一些旧的东西
如C语言的结构体
C++中的结构体,不仅保留了原来的可以声明变量,甚至向类看齐,能在结构体中声明和定义函数
C++中结构体和类的共同点
- 能声明和定义函数
- 能声明变量
当一个类没有主动设置访问限定符的时候,C++会默认它的所有成员的访问限定符是private
当一个结构体没有主动设置昂文限定符的时候,C++会默认它的所有成员的访问限定符是public
C++中结构体和类的不同点
- C++的类的默认访问限定符是private
- C++的结构体默认访问限定符是public
总结
标签:函数,对象,C++,限定符,指针,属性 From: https://blog.csdn.net/2402_85267481/article/details/143815047本文章相当于C++的正式入门,我们真正认识到了什么是面向对象,以及它的好处,在C++中是怎么体现的,后续的文章中,我们将继续介绍类,将类吃透
有问题,欢迎在评论区讨论
觉得有所帮助,麻烦点个赞,关注一下