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
2
3
4
5
class Human{
public:
private:
static unsigned int s_eye_num; //前面加上static即可,注意,此处只是声明,我们还未定义,不能直接使用,必须进行定义及初始化操作
};

定义

通常情况下,我们将静态变量定义放在类外的cpp文件中进行定义,切记不要再头文件中对静态变量进行初始化。如果放在.h文件中,每一个包含该头文件的文件都会去重复定义类的静态变量,从而产生链接错误。正确的做法是对所有的类静态成员在类的实现cpp文件中进行统一定义及初始化管理。

1
unsigned int Human::s_eye_num = 0;      //定义及初始化,只能进行一次

访问控制

静态类成员可以设置为public或private的,当设置为public时,可以通过作用域方式访问,即:

1
2
3
4
5
int main(){
Human duanshiqi;
cout << Human::s_eye_num << endl;
cout << duanshiqi.s_eye_num << endl; //正确!属于类的肯定也是属于每一个对象的
}

而私有时则必须通过相应的get函数进行访问。

类在内存中的分布

在内存中,类从高字节向低字节增长,例如我们给定下面一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Trapframe {
struct PushRegs tf_regs;
uint16_t tf_es;
uint16_t tf_padding1;
uint16_t tf_ds;
uint16_t tf_padding2;
uint32_t tf_trapno;
/* below here defined by x86 hardware */
uint32_t tf_err;
uintptr_t tf_eip;
uint16_t tf_cs;
uint16_t tf_padding3;
uint32_t tf_eflags;
/* below here only when crossing rings, such as from user to kernel */
uintptr_t tf_esp;
uint16_t tf_ss;
uint16_t tf_padding4;
} __attribute__((packed));

那么这个类在内存中的分布即为,与类定义正好相反:

图片名称

参考文献

0%