六一的部落格


关关难过关关过,前路漫漫亦灿灿。



继承引入了protected关键字:

  1. 类的用户无法访问
  2. 派生类的成员和友元可以通过派生类对象来访问基类的受保护成员; 对基类对象的成员不具有特殊的访问权限
  3. 友元和成员函数可以访问

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

  1. 派生类公有的继承基类, 用户代码可以使用派生类向基类的转换
  2. 派生类向其直接基类的类型转换对于派生类的成员函数和友元永远都是可访问的
  3. 如果直接派生类私有继承基类, 间接派生类无法使用直接派生类到基类的转换
 1#include <iostream>
 2
 3using namespace std;
 4
 5class FooBase
 6{
 7public:
 8    FooBase(int aa) : a(aa) {}
 9    FooBase() : FooBase(0) {}
10
11    void printFooBase() { cout << a; }
12
13private:
14    int a;
15};
16
17class Foo : protected FooBase
18{
19    friend void testFunction(Foo &f);
20
21public:
22    void printFoo() { printFooBase(); }
23};
24
25void testFunction(Foo &f)
26{
27    FooBase &fb = f;      // 正确: testFunction为Foo的友元, 可以使用派生类到基类的转换
28    fb.printFooBase();
29    cout << endl;
30}
31
32int main()
33{
34    Foo f;
35    FooBase &fb = f;      // 错误: Foo派生为protected
36
37    testFunction(f);      
38
39    return 0;
40}

类的设计


不考虑继承时

类的用户有两种:

  1. 程序员, 使用类的公有接口和友元
  2. 类的设计者, 实现成员函数和友元, 既可以访问类的公有部分, 也能使用类的私有(实现)部分

加入继承

第三种用户: 派生类

基类仍提供接口供类的用户使用 public , 但把实现分为两部分:

  1. 供派生类访问 protected

    派生类在实现自己的功能时可以使用基类的这些操作和数据
  2. 供基类自己及其友元访问 private

友元关系既不能传递, 也不能继承

  1. 基类友元可以通过派生类对象访问基类部分
  2. 派生类友元只能通过派生类对象访问基类部分
 1class Base
 2{
 3    friend class Pal;                          // Pal可以访问Base对象, 以及派生类对象中的Base子对象
 4protected:
 5    int prot_mem;
 6};
 7
 8class Sneaky : public Base
 9{
10    int j;
11};
12
13class Pal
14{
15public:
16    int f(Base b) { return b.prot_mem; }        // 正确: Pal是Base的友元
17    int f2(Sneaky s) { return s.j; }            // 错误: j并不属于Base子对象
18    int f3(Sneaky s) { return s.prot_mem; }     // 正确: Sneaky派生自Base, prot_mem属于Base子对象 
19};
20
21class D2 : public Pal
22{
23public:
24    int mem(Base b) { return b.prot_mem; }     // 错误: 友元关系不能继承
25};

每个类负责控制各自成员的访问权限


改变个别成员的可访问性

通过 using 声明

将直接基类或间接基类中的可访问成员标记为新的访问权限

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

 1class Base
 2{
 3public:
 4    size_t size() const { return n; }
 5protected:
 6    size_t n;    
 7};
 8
 9class Derived : private Base
10{
11public:
12    using Base::size;         // Base的成员到了Derived变为private, 重新设置为public
13protected:
14    using Base::n;            // Base的成员到了Derived变为private, 重新设置为protected
15};

访问控制与继承


继承引入了protected关键字:

  1. 类的用户无法访问
  2. 派生类的成员和友元可以通过派生类对象来访问基类的受保护成员; 对基类对象的成员不具有特殊的访问权限
  3. 友元和成员函数可以访问

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

  1. 派生类公有的继承基类, 用户代码可以使用派生类向基类的转换
  2. 派生类向其直接基类的类型转换对于派生类的成员函数和友元永远都是可访问的
  3. 如果直接派生类私有继承基类, 间接派生类无法使用直接派生类到基类的转换
 1#include <iostream>
 2
 3using namespace std;
 4
 5class FooBase
 6{
 7public:
 8    FooBase(int aa) : a(aa) {}
 9    FooBase() : FooBase(0) {}
10
11    void printFooBase() { cout << a; }
12
13private:
14    int a;
15};
16
17class Foo : protected FooBase
18{
19    friend void testFunction(Foo &f);
20
21public:
22    void printFoo() { printFooBase(); }
23};
24
25void testFunction(Foo &f)
26{
27    FooBase &fb = f;      // 正确: testFunction为Foo的友元, 可以使用派生类到基类的转换
28    fb.printFooBase();
29    cout << endl;
30}
31
32int main()
33{
34    Foo f;
35    FooBase &fb = f;      // 错误: Foo派生为protected
36
37    testFunction(f);      
38
39    return 0;
40}

类的设计


不考虑继承时

类的用户有两种:

  1. 程序员, 使用类的公有接口和友元
  2. 类的设计者, 实现成员函数和友元, 既可以访问类的公有部分, 也能使用类的私有(实现)部分

加入继承

第三种用户: 派生类

基类仍提供接口供类的用户使用 public , 但把实现分为两部分:

  1. 供派生类访问 protected

    派生类在实现自己的功能时可以使用基类的这些操作和数据
  2. 供基类自己及其友元访问 private

友元关系既不能传递, 也不能继承

  1. 基类友元可以通过派生类对象访问基类部分
  2. 派生类友元只能通过派生类对象访问基类部分
 1class Base
 2{
 3    friend class Pal;                          // Pal可以访问Base对象, 以及派生类对象中的Base子对象
 4protected:
 5    int prot_mem;
 6};
 7
 8class Sneaky : public Base
 9{
10    int j;
11};
12
13class Pal
14{
15public:
16    int f(Base b) { return b.prot_mem; }        // 正确: Pal是Base的友元
17    int f2(Sneaky s) { return s.j; }            // 错误: j并不属于Base子对象
18    int f3(Sneaky s) { return s.prot_mem; }     // 正确: Sneaky派生自Base, prot_mem属于Base子对象 
19};
20
21class D2 : public Pal
22{
23public:
24    int mem(Base b) { return b.prot_mem; }     // 错误: 友元关系不能继承
25};

每个类负责控制各自成员的访问权限


改变个别成员的可访问性

通过 using 声明

将直接基类或间接基类中的可访问成员标记为新的访问权限

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

 1class Base
 2{
 3public:
 4    size_t size() const { return n; }
 5protected:
 6    size_t n;    
 7};
 8
 9class Derived : private Base
10{
11public:
12    using Base::size;         // Base的成员到了Derived变为private, 重新设置为public
13protected:
14    using Base::n;            // Base的成员到了Derived变为private, 重新设置为protected
15};