访问控制与继承
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;
};
void clobber(Sneaky &s) {
s.j = s.prot_mem = 0; // 正确
}
void clobber(Base &b) {
b.prot_mem = 0; // 错误
}
友元函数可以访问Sneaky
的所有成员,所以访问私有的j
和受保护的prot_mem
都没问题
但是它不是Base
的友元,所有不能访问Base
的受保护成员
某个类对其继承而来的成员的访问权限受到两个因素的影响:
- 在基类中该成员的访问说明符
- 在派生类的派生列表中的访问说明符
两者取权限较小的
class Base {
public:
void pub_mem();
protected:
int prot_mem;
private:
char priv_mem;
};
struct Pub_Derv : public Base {
int f() { return prot_mem; } // 正确
int g() { return priv_mem; } // 错误
};
struct Priv_Derv : private Base {
int f1() { return prot_mem; } // 正确
};
Pub_Derv
类中有从Base
继承而来的public
的pub_mem
成员,还有protected
的prot_mem
成员,但是没有private
的priv_mem
成员
Priv_Derv
类中有从Base
继承而来的private
的pub_mem
,还有private
的priv_mem
,在类内可以访问
Pub_Derv d1;
Priv_Derv d2;
d1.pub_mem(); // 正确
d2.pub_mem(); // 错误,不能访问private成员
- 派生访问说明符的目的是控制派生类用户对于基类成员的访问权限
- 派生访问说明符还可以控制继承派生类的新类的访问权限
struct Derived_from_Public : public Pub_Derv {
int use_base() { return prot_mem; } // protected
};
struct Derived_from_Private : public Priv_Derv {
int use_base() { return prot_mem; } // 错误,不能继承基类的private成员
};
public
权限
- 用户可以访问
- 类内部,继承类和友元函数可以访问
protected
权限
- 用户不能访问
- 类内部,继承类和友元函数可以访问
private
权限
- 用户不能访问
- 继承类不能访问
- 类内部和友元函数可以访问
友元与继承:友元不能继承
class Base {
friend class Pal;
protected:
int prot_mem;
};
class Pal {
public:
int f(Base b) { return b.prot_mem; } // 正确,友元可以访问所有类的成员
int f2(Sneaky s) { return s.j; } // 错误,友元不能访问派生类的私有成员
int f3(Sneaky s) { return s.prot_mem; } // 正确,友元可以访问派生类的基类部分
};
Pal
能够访问Base
的成员,这种访问包括了Base
对象内嵌在其派生类对象中的情况
对基类的访问权限由基类本身控制,即使对于派生类的基类部分也是如此
class D2 : public Pal {
public:
int mem(Base b) { return b.prot_mem; } // 错误,友元不能继承
};
可以使用using
改变个别成员的可访问性
class Base {
public:
size_t size() const { return n; }
protected:
size_t n;
};
class Derived : private Base { // private继承
public:
using Base::size;
protected:
using Base::n;
};
相当于修改了原本的访问说明符,私有继承之后本来都是private
,修改为public
和protected
派生类只能为那些它可以访问的名字提供
using
声明
默认的继承保护级别
class Base {};
struct D1 : Base {}; // 默认public继承
class D2 : Base {}; // 默认private继承