C++类和对象(上篇)
Posted Suk-god
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++类和对象(上篇)相关的知识,希望对你有一定的参考价值。
文章目录
面向过程 && 面向对象
面向过程
,关注的是过程,分析求解问题的步骤,通过函数调用逐步解决问题
C++是基于面向对象的
。关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成
类 && 对象
概念区分
类
:用来对实体(对象)进行描述,对象有什么属性以及对象具有什么功能。是一种自定义类型
对象
:现实生活中实实在在存在的,对象是类的具体表现
。用类类型创建出来的变量—>对象
类的定义
使用struct和class都可以定义类,在C++中一般使用class定义类
格式:
class classname.........;
class:定义类的关键字
classname:类的名称
…为类的主体,以;
结尾类中的元素称为类的成员
类中的数据称为类的属性或者成员变量
类中的函数称为类的方法或者成员函数
- 类的两种定义方式
1、声明和定义都放在类体中
注意:成员函数如果在类中定义
,编译器可能会
将其当做内联函数
处理
2、声明和定义分开
一般情况下,推荐使用方式2
类的访问限定符及封装
访问限定符
限定符种类
- public(公有)
修饰的成员在类外可以直接被访问 - protected(保护)
修饰的成员在类外不能直接被访问 - private(私有的)
修饰的成员在类外不能直接被访问
目前看来,protected与private没有什么区别(实质上并不是,后续学到后再补充)
限定符作用域
访问权限的作用域从该访问限定符出现的地方开始,直到下一个访问限定符出现为止
几点补充
- class的默认访问权限为private,struct的默认访问权限为public(因为要兼容C)
- 访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
面试题:C++中
class
和struct
的区别是什么
解答:
- C++需要兼容C语言,所以C++中的struct可以当做结构体去使用。
- C++中的struct还可以定义类,和class定义类是一样的。区别是struct的类成员默认访问方式是public,class的类成员默认访问方式private
封装
什么是封装?
将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
C++如何实现封装的?
用类将对象的属性和方法结合在一块,让对象更加完善。通过访问权限选择性的将其接口提供给外部的用户使用
面向对象的三大特征
封装 继承 多态
有时候会说四大特征:在原有的基础上增加一个抽象
抽象:对一个复杂事物的认知过程
类的作用域
C++中的作用域
- 全局作用域
- 函数体内部的局部作用域
- 命名空间
- 类域
类域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 ::
作用域解析符指明成员属于哪个类域。
类的实例化
用类类型创建对象的过程称为类的实例化
类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
类对象模型
计算类对象的大小
分析:类实例化出来的对象中不仅有成员变量
,还有成员函数
。
因此我们就有以下几种设想:
-
计算一个类的大小是类中成员变量的大小 + 成员函数的大小
-
成员函数单独存储一份,不同的变量调用同一个成员函数,因此只需要计算成员变量的大小 + 一个指针的大小(该指针指向单独存储的成员函数)
接下来我们实际验证一波儿
事实告诉我们我们上面的两种设想都是错误的!!!
结论
一个类的大小,实际就是该类中成员变量之和,当然也要进行内存对齐!!!
空类的大小是多少呢?
测试一把
在VS013环境下:
关于空类大小为1的原因解释见下图:
在Linux环境下
它的结果也是1
类对象的存储方式
事实证明,在计算类对象大小的时候,不需要考虑成员函数,因为成员函数是被存储在公共代码区的
一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
几道面试题
- 结构体如何对齐,为什么要进行内存对齐??
如何对齐,主要有4步骤
:
①第一个成员在与结构体偏移量为0的地址处
②其他成员变量要对齐到某个数(对齐数)的整数倍的地址处
对齐数指的是min(编译器默认对齐数,成员变量大小)其中VS的默认对齐数是8
③结构体总的大小要满足最大对齐数的整数倍
④如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍。结构体整体的大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
为什么要进行内存对齐,原因有两点
:
第一:平台原因
不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
第二:性能原因
数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐的内存。处理器需要做两次内存访问。而对齐后的内存访问只需要一次访问。
总的来说,结构体内存对齐是拿空间换时间的做法 - 如何让结构体按照指定的对齐参数进行对齐
使用预处理命令
设置默认对齐数
#pragma pack(xxx) //xxx:想要设置的默认对齐数
恢复默认对齐数
#pragma pack()
结构体在对齐方式不合适的时候,我们可以自己更改默认对齐数
-
什么是大小端?如何测试某台机器是大端还是小端。
大小端
:说的是数据在内存当中存储的两种不同方式
测试大小端的3种方式
:
①对一个整型变量赋初值为1,然后采用char*的指针去访问这个整数
我的机器为小端
②采用联合结构union
小端,验证完毕
③通过在VS中查看内存布局确定
-
空类有多大,为什么?
this指针
引入
问题:在Init() 和 Print()成员函数中,没有任何关于对象的说明,那这些成员方法在执行的时候,是如何知道要对哪个对象操作的?
这就是this指针的作用
!!
即:C++中通过引入this指针解决该问题,即C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(程序运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
this的特性
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
面试题
- this指针存在哪里?
解答:this指针存放在栈上
验证:
思路:定义this的引用类型变量,打印this的地址与esp(栈顶)ebp(栈底)地址比较,如果在两者之间,就说明是在栈上定义的
- this指针可以为空吗?
解答:可以!
但是当this指针为空后,在调用成员函数的时候可能会崩溃。
上面是对类的定义
紧接着看下面的代码片段
首先,它是可以通过编译的,指针P的值会由编译器传递给this指针,那么也就是说,this指针是可以为空的。
紧接着我们向下运行代码:
紧接着进入Init函数的内部
我们发现程序崩溃了。
总结一下:
this指针可以为空,当this指针为空的时候,如果在成员函数中没有访问任何成员变量或者成员函数,则代码不会崩溃,否则就会崩溃。
OK~~
以上就是本次的全部内容!各位看官请留下你们的足迹~~
以上是关于C++类和对象(上篇)的主要内容,如果未能解决你的问题,请参考以下文章
C++初阶:类和对象(上篇)类的定义 | 类的访问限定符及封装 | 类的作用域 | 类的实例化 | 类对象模型 | this指针