【C++ 继承】借助指针突破访问权限的限制,访问private、protected属性的成员变量


1) public继承方式

  • 基类中所有 public 成员在派生类中为 public 属性;

  • 基类中所有 protected 成员在派生类中为 protected 属性;

  • 基类中所有 private 成员在派生类中不能使用。


2) protected继承方式

  • 基类中的所有 public 成员在派生类中为 protected 属性;

  • 基类中的所有 protected 成员在派生类中为 protected 属性;

  • 基类中的所有 private 成员在派生类中不能使用。


3) private继承方式

  • 基类中的所有 public 成员在派生类中均为 private 属性;

  • 基类中的所有 protected 成员在派生类中均为 private 属性;

  • 基类中的所有 private 成员在派生类中不能使用。

 

访问控制

protected成员:

  • 和私有成员类似,受保护成员对于类的用户来说是不可访问的。
  • 和公有成员类似,受保护成员对于派生类的成员和友元来说是可访问。
  • 派生类的成员或友元只能通过派生类对象来访问基类的受保护成员,派生类对于一个基类对象中的受保护成员没有任何访问特性。

1. 实例

#include <iostream>
using namespace std;

class Base {
public:
    Base(): prot_men(0), pub_men(0) {}
protected:
    int prot_men;
public:
    int pub_men;
};

class Sneaky: public Base {
    friend void clobber(Sneaky &s);
    friend void clobber(Base &b);
    int j{-1};
};
// 正确:clobber能访问Sneaky对象private和protect成员
void clobber(Sneaky &s) {s.j = s.prot_men = 0; }
// 错误:clobber不能访问Base的protected成员
void clobber(Base &b) {b.prot_men = 0;}

int main()
{
    Sneaky s;
    clobber(s);
}

 

 

实例2

#include <iostream>
using namespace std;

class Base {
public:
    Base(): prot_men(0), pub_men(0) {}
protected:
    int prot_men;
public:
    int pub_men;
};

class Sneaky: protected Base {
    friend void clobber(Sneaky &s);
    int j{-1};
};
void clobber(Sneaky &s) {s.j = s.prot_men = 0; }

int main()
{
    Sneaky s;
    clobber(s);
}

 

 

总结:

派生类说明符对于派生类成员以及友元能访问其直接基类的成员没有任何成员,对基类成员的访问权限只与基类中的访问说明符有关。

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

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

class A {};
class B : public A {}

void function(const A&) {}

int main()
{
    B b;
    function(b); // 这时就可以使用function(b),会默认把B类型转换成A类型。
}
 1 class A {};
 2 class B : public A {}
 3  
 4 void function(const A&) {}
 5  
 6 int main()
 7 {
 8     B b;
 9     function(b); // 这时就可以使用function(b),会默认把B类型转换成A类型。
10 }

 

 

 

2. 不论D以什么方式继承B,D的成员函数和友员函数都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员函数和友员函数来说永远是可访问的。

1 class B {};
2 class D : private B   //这里以private或者protected或者public 都可以
3 {
4     void f()
5     {
6         B * base = new D;   //编译正确
7     }
8 }

如果不是成员函数(即用户代码),例如:

 1 class B {};
 2 class D : private B     //如果这里是public就可以,private或protected会错
 3 {
 4     void f()
 5     {
 6         B * base=new D;
 7     }    
 8 };
 9 
10 int main()
11 {
12     B * b = new D;    //会出现编译错误,注意,这是用户代码
13 };

 

 

3. 如果D继承B的方式是public或者protected,则D的派生类的成员或者友员可以使用D向B的类型转换;反之,如果D继承B的方式是private,则不能使用。

 1 class B {};
 2 class D : public B {}; //public或protected都可以
 3 class E : private D    //或者protected D 或者public D
 4 {
 5     void f()
 6     {
 7         B *b = new D;   //可以编译通过
 8         D *d = new E;   //可以编译通过,这就是2介绍的情况。
 9     }
10 };
class B {};
class D : public B {}; //public或protected都可以
class E : private D    //或者protected D 或者public D
{
    void f()
    {
        B *b = new D;   //可以编译通过
        D *d = new E;   //可以编译通过,这就是2介绍的情况。
    }
};

 对于代码中的某个给定节点来说,如果基类的公有成员时可访问的,则派生类向基类的类型转换也是可访问的,反之则不行。

参考资料

posted @ 2018-09-18 21:56  苏格拉底的落泪  阅读(524)  评论(0编辑  收藏  举报