Fork me on GitHub

访问控制与继承

访问控制与继承

每个类分别控制自己的成员初始化过程,与之类似,每个类还分别控制着其成员对于派生类来说是否可访问(accessible)。

受保护的成员

  • 和私有成员类似,受保护的成员对于类的用户来说是不可访问的。
  • 和共有成员类似,受保护的成员对于派生类的成员和友元来说是可访问的。

此外,protected还有另外一条重要的性质。

  • 派生类的成员或友元只能通过派生类对象来访问基类受的保护成员。派生类对于一个基类对象中的受保护的成员没有任何访问权限

考虑如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base{
protected:
int prot_mem;
};
class Sneaky : public Base {
friend void clobber(Sneaky&); //能访问Sneaky::prot_mem
friend void clobber(Base&); //不能访问Base::prot_mem
int j;
};
//正确:clobber能访问Sneaky对象的private和protected成员
void clobber(Sneaky &s) {s.j = s.prot_mem = 0;}
//错误:clobber不能访问Base的protected成员
void clobber(Base &b){ b.prot_mem = 0;}

公有、私有和受保护继承 (重点)

某个类对其继承而来的成员的访问权限受到两个因素影响:一是在基类中该成员的访问说明符,二是在派生类的派生列表中的访问说明符。

派生类访问说明符(继承的类是公有、私有还是受保护)对于派生类的成员(及友元)能否访问其直接基类的成员没有影响,基类成员的访问权限只与基类中的访问说明符有关(派生类的成员不能访问基类私有成员,可以访问基类公有和受保护成员)。

派生类访问说明符的目的是控制派生类用户(包括派生类的派生类在内)对于基类成员的访问权限:

  • 如果继承是公有的,对于派生类用户来讲,基类中成员遵循其原有的访问说明符。
  • 如果继承是私有的,对于派生类用户来讲,基类中的成员访问说明符都是私有的。
  • 如果继承是受保护的,对于派生类用户来讲,基类的所有公有成员在新定义的类中都是受保护的,基类中的受保护和私有成员遵循原来的访问说明符。

派生类向基类转换的可访问性 (略)

  • 只有当D公有地继承B时,用户代码才能使用派生类向基类的转换;如果D继承B的方式是受保护或者私有的,则用户代码不能使用该转换。

关键概念:类的设计与受保护的成员

不考虑继承的话,我们可以认为一个类有两种不同的用户:普通用户和类的实现者。其中,普通用户编写的代码使用类的对象,这部分代码只能访问类的公有(接口)成员;实现者则负责编写类的成员和友元的代码,成员和友元既能访问类的公有部分,也能访问类的私有(实现)部分。

如果进一步考虑继承的话就会出现第三种用户:即派生类。基类把它希望派生类能够使用的部分声明成受保护的。普通用户不能访问受保护的成员,而派生类及其友元仍旧不能访问私有成员。

和其他类一样,基类应该将其接口成员声明为公有的;同时将属于其实现的部分分成两组:一组可以供派生类访问,另一组只能由基类及基类的友元访问。对于前者应该声明为受保护的,这样派生类就能在实现自己的功能时使用基类的这些操作和数据;对于后者应该声明为私有的。

友元与继承

不能继承友元关系;每个类负责控制各自成员的访问权限。

改变个别成员的可访问性

有时我们需要改变派生类继承的某个名字的访问级别,通过使用using声明可以达到这一目的。

派生类只能为那些它可以访问的名字提供using声明。

默认的继承保护级别

使用class关键字定义的派生类是私有继承的;而使用struct关键字定义的派生类是公有继承的。

一个私有派生类最好显式地将private声明出来,而不要仅仅依赖于默认的设置。显式声明的好处是可以令私有继承关系清晰明了,不至于产生误会。

-------------本文结束感谢您的阅读-------------

本文地址:http://www.wangxinri.cn/2017/11/23/访问控制与继承/
转载请注明出处,谢谢!

梦想夹带眼泪,咸咸的汗水!