成员访问的三种权限
面试官: 在 C++ 的类(class)定义中,我们有 public, protected, 和 private 这三个关键字来控制成员的访问权限。
你能简单解释一下,这三种权限分别意味着什么吗?也就是说,什么样的代码可以访问被它们修饰的成员?
回答:
public修饰的成员,可以被该类的对象、该类的子类成员,以及该类的其他成员访问。(最宽松)private修饰的成员,只能被该类的其他成员访问,而不能被对象和子类成员访问。(最严格)protected修饰的成员,可以被该类的其他成员和子类的成员访问,但不能被该类的对象访问。(介于public和private之间)
Gemini 更好的概括:
public: 类内、子类、类外(通过对象)都能访问。权限最开放。private: 仅限类内访问。权限最严格,实现了完全的封装。protected: 类内、子类可以访问,但类外不行。权限介于两者之间,专门为继承体系设计。
类继承的三种权限
面试官 (深入提问): 好的,你对成员访问权限很清楚。现在我们把这个概念和继承结合起来。
C++ 中,继承也有三种方式:public 继承、protected 继承和 private 继承。
| |
请问,这三种不同的继承方式,会如何影响基类 (Base) 的成员在派生类 (Derived) 中的访问权限?
换句话说:
- 在
Derived_Public内部,public_member和protected_member分别是什么权限? - 在
Derived_Protected内部呢? - 在
Derived_Private内部呢? - 基类的
private_member在任何情况下,派生类能访问到吗?
回答:
首先,private 成员是基类私有的,派生类无法触及。因此,任何情况下,派生类都访问不到。
其次,关于其他成员的继承,我们有如下黄金法则:
基类成员在派生类中的最终访问权限,取决于两者中更严格(权限更小)的那个。
这里说的“两者”,指的就是基类成员本身的访问权限,和派生类继承基类时的权限。
用下面的表格很好理解:
| 基类成员权限 | public 继承后 | protected 继承后 | private 继承后 |
|---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | (不可访问) | (不可访问) | (不可访问) |
其中 public 继承是我们平时用得最多的,它的行为也最符合直觉。protected 和 private 继承在实际工程中用得相对较少,但理解它们有助于我们完整地掌握 C++ 的权限体系。
因此,上面问题的答案是:
- 在
Derived_Public内部,public_member为public权限,protected_member为protected权限,与基类中一致。 - 在
Derived_Protected内部,public_member和protected_member均为protected权限。 - 在
Derived_Private内部,public_member和protected_member均为private权限。 - 在任何情况下,基类的
private_member都无法被派生类访问。
struct 和 class 之间的辨析
面试官 (最终问题): 很好,你对成员权限和继承权限都有了清晰的理解。现在我们来聊一个 C++ 中特有的概念:struct 和 class。
在 C++ 中,struct 和 class 都可以用来定义一个类,它们都可以有成员变量、成员函数、构造函数、析构函数,也都可以进行继承。
从功能上看,它们几乎是一样的。那么,请问 struct 和 class 在 C++ 中,它们唯一的区别是什么?
另外,从编程风格和设计意图上讲,我们通常在什么情况下倾向于使用 struct,又在什么情况下倾向于使用 class?
回答:
- 我认为,它们之间唯一的区别是:如果没有明文规定,那么
struct所有的成员权限默认为public,而class的所有成员权限默认为private。 - 从编程风格和设计意图上来说,
- 如果需要设计一个功能简单、关系较少的类,我们倾向于使用
struct - 如果需要设计一个功能复杂、关系很多,且需要设计对外接口的类,我们倾向于使用
class
- 如果需要设计一个功能简单、关系较少的类,我们倾向于使用
面试官 (总结与肯定): 你说的完全正确。
1. 唯一的语法区别:默认访问权限
struct: 成员的默认访问权限是public。class: 成员的默认访问权限是private。
这也是它们与 C 语言中 struct 行为保持某种兼容性的体现(C 的 struct 成员都是公有的)。
| |
2. 编程风格和设计意图的区别
你对这一点的理解,正是一名优秀 C++ 程序员应有的素养。这已经超出了“语法”的范畴,进入了“代码设计哲学”的层面。
使用
struct的场景:- 当我们想定义一个纯粹的数据集合 (Plain Old Data, POD) 时。
- 这个数据结构的主要职责就是聚合数据,而没有什么复杂的行为(成员函数)或不变量(需要
private保护的内部状态)。 - 比如,一个
Point结构体,包含x和y坐标;一个RGBColor结构体,包含r,g,b三个分量。这些成员通常都是public的,因为它们就是这个结构体存在的全部意义。
使用
class的场景:- 当我们想定义一个拥有复杂行为和内部状态的对象时。
- 这个对象需要通过
public接口来对外提供服务,同时需要用private或protected来隐藏(封装) 其内部的实现细节和数据,以保证其不变量 (invariants) 不被破坏。 - 比如,一个
FileDownloader类,它内部可能有private的socket_、buffer_等成员,对外只提供public的download()、getProgress()等接口。
总结来说,选择 struct 还是 class,更多的是向其他阅读代码的人传递一种设计意图的信号:我这里定义的是一个简单的数据包 (struct),还是一个具有封装性的、有复杂行为的对象 (class)。