God said, Let there be light: and there was light.
作为一门面向对象语言,C++允许我们使用类进行自定义类型,本文将针对类中的一些问题进行相关总结。
访问控制
封装是面向对象的一个重要特点,它对外部函数或对象访问类内部的成员的过程进行限制。C++提供了三种访问修饰符,分别是public,protected和private,本节将对这三种修饰符进行总结。
public
保密性最低,可以直接通过对象引用的方式访问,一般来说对外暴露的接口定义为public
。
private
保密性最高,私有成员变量或函数在类外不可访问,甚至不能查看,只有类和友元函数能访问私有成员。在实际编程中,能使用private
,就使用private
。
protected
protected一般用在继承当中,它和private很相似,protected成员变量或函数在类外不能被访问,但是在派生类(子类)中是可以访问的。在继承中,如果需要子类访问基类的数据和函数,而外部成员不需要访问,那么可以将这些数据定义为protected。
继承中的特点
在继承中有三种继承的方式,这里我们总结一下不同的访问修饰符在继承下的基类成员访问属性
继承方式 | 基类成员 | 在子类中的访问属性 |
---|---|---|
public | public | public(子类可访问,外部可访问) |
protected | protected(子类可访问,外部不能访问) | |
private | private(子类不能访问) | |
protected | public | protected(子类可访问,外部不能) |
protected | protected(子类可访问,外部不能) | |
private | private(子类不能访问,外部不能) | |
private | public | private (子类可以访问,对外为private) |
protected | private(子类可以访问,对外为private) | |
private | private(子类不可访问) |
无论哪种继承,有两点没有变化
- private只能由本类或有源访问,子类也不能访问
- protected成员可以被子类访问
这里其实挺迷惑的,从逻辑上讲,子类是包含在基类当中的,理应具有并且能够访问基类的所有属性,但是事实上,子类也可以视为基类的使用者,也是基类的客户代码,如果基类的方法是private,但是子类可以访问,那么完全可能发生下面的事情:我创建了一个子类,然后继承这个基类,这样我就可以访问基类中的private方法,其实这样就严重破坏了数据封装性的原则。
静态类成员
有些情况下,某个数据成员应当属于类而非具体对象本身。例如我们说正常人都有两只眼睛,那么眼睛的数量应当是与人直接相关而非与特定个体相关。当我们更改了眼睛的数量,应当所有的个体眼睛数量都会被修改。那么此时我们需要定义类的静态成员,它属于类本身,而非某个个体。
声明及定义静态类成员
声明
1 | class Human{ |
定义
通常情况下,我们将静态变量定义放在类外的cpp文件中进行定义,切记不要再头文件中对静态变量进行初始化。如果放在.h文件中,每一个包含该头文件的文件都会去重复定义类的静态变量,从而产生链接错误。正确的做法是对所有的类静态成员在类的实现cpp文件中进行统一定义及初始化管理。
1 | unsigned int Human::s_eye_num = 0; //定义及初始化,只能进行一次 |
访问控制
静态类成员可以设置为public或private的,当设置为public时,可以通过作用域方式访问,即:
1 | int main(){ |
而私有时则必须通过相应的get函数进行访问。
类在内存中的分布
在内存中,类从高字节向低字节增长,例如我们给定下面一个类:
1 | struct Trapframe { |
那么这个类在内存中的分布即为,与类定义正好相反: