C++Primer读书笔记(一)-访问控制与继承

​ 每个类通过成员访问运算符控制其成员对于派生类和类的用户来说是否是可访问的。

受保护的成员

​ 一个类使用protected关键字来声明那些希望与派生类分享但不想被其他用户访问的成员。可以说protected是夹在private成员和public成员的中和产物。主要有以下三条性质

  1. 受保护成员对于类的用户者不可访问
  2. 受保护成员对于派生类的成员和友元是可访问
  3. 派生类的成员或者友元只能通过派生类对象来访问基类的受保护成员,派生类对于一个基类对象中的受保护成员没有访问权限。即派生类的成员和友元只能访问派生类对象中的基类部分的受保护成员(管好自家),而对一个普通基类对象中的受保护成员是没有访问权限的。

第三点举例

1
2
3
4
5
6
7
8
9
10
//定义基类
class Base{
protected:
int prot_mem;
};
//定义派生类
class Sneaky: public Base{
friend void clobber(Sneaky&); //能访问Sneaky::prot_mem
friend void clobber(Base&); //不能访问Base::proe_mem 对于一个基类对象中的受保护成员没有访问权限
};
类本身 类的实例化对象(类的用户) 类的派生
public成员
private成员 X X
protected成员 X

√表示可访问,X表示不可访问

三种继承方式——公有、私有和受保护继承

​ 不加声明,class默认私有继承,struct默认公有继承

​ 类对其继承而来的成员的访问权限收到两个因素影响:1.基类中的成员访问符 2. 派生列表的访问说明符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//定义基类
class Base{
public:
void pub_mem();
private:
char priv_mem;
protected:
int prop_men;
};

//定义公有派生
class Pub_Derv:public Base{
//正确,可访问基类部分的受保护成员
int f(){return prop_men;}

//错误,不能访问基类部分的私有成员
//char g(){return priv_mem;}
}

//定义私有派生
class Pri_Derv:private Base{
//正确,派生列表中访问说明符不影响派生类对于基类部分的访问权限
int f1(){return prop_men;}
};

​ 派生列表的访问说明符不影响派生类对基类部分成员的访问权限,这只与基类中的成员访问符有关,派生列表中的访问说明符的目的是

控制派生类用户(包括派生类的派生)对于基类成员的访问权限

1
2
3
4
Pub_Derv d1;
Pri_Derv d2;
d1.pub_mem(); //正确
//d2.pub_mem() //错误,经过私有继承后,基类中的公有成员对于派生类用户不可访问

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

派生类向基类转换: 基类的指针指向派生类或者基类的引用绑定到派生类对象(实际上是指向或者绑定到派生类的基类部分)

  • 只有当派生类公有的继承基类,用户代码才能使用派生类向基类转换。私有和保护继承都不行
  • 派生类的成员函数和友元都能使用派生类向基类的转换,与继承方式无关
  • 如果派生类是公有或者保护继承基类,那么派生类的派生类的成员函数和友元可以实现派生类向其基类的转换

类的设计小tip

​ 类有三种用户:类的实现者、派生类以及类的使用者。基类应该将接口成员声明为公有;同时将实现部分分成两组:1.声明为protected供派生类访问 2. 声明为private共基类自身和基类的友元访问

类的用户 访问权限
类的实现者 全部
类的使用者 类的公共接口
派生类 类的保护成员

友元与继承

​ 友元关系不能传递也不能继承,每个类负责自己的成员的访问权限。基类的友元只能访问基类,不能访问它的派生类本身成员,但是可以访问派生类中的基类部分的成员。

1
2
3
4
5
6
7
8
class Base{
friend class Pal; // 友元声明
};
class Pal{
int f(Base b){return b.prot_mem;} //正确
//int f2(Sneaky s){return s.j;} //错误 不能访问派生类本身成员
int f3(Sneaky s){return s.prot_mem;} //正确,可以访问派生类中的基类部分的成员
}