引入三种访问控制符
C++ 中, 存在三种访问控制修饰符, 它们分别是:
- public // 公有成员
- protected // 保护成员
- private // 私有成员
术语
为了使文章容易理解, 我们首先对以下术语作出说明:
对象: 与类相对, 对象是类的实例.
派生类: 与基类相对, 派生类就是子类.
继承: 继承与派生是一个意思. 继承偏重指出此过程中不变的部分, 而派生则偏重于在原有基础上新增的部分.
成员: 类中成员变量和成员函数的统称.
对象的访问权限
在以下的例子中, 我们创建了一个简单的类.
下面, 我们就来探究一下, 对于该类中被不同访问控制修饰符修饰的成员, 该类的对象都有什么样的访问权限.
- #include <iostream>
- using namespace std;
- class CBase
- {
- private:
- int a_base_private;
- protected:
- int b_base_protected;
- public:
- int c_base_public;
- public:
- CBase(){a_base_private = 1; b_base_protected = 2; c_base_public = 3;}
- ~CBase(){}
- int getA() const {return a_base_private;} // OK, 类可以访问自身的所有成员
- int getB() const {return b_base_protected;} // OK, 类可以访问自身的所有成员
- int getC() const {return c_base_public;} // OK, 类可以访问自身的所有成员
- };
- int main()
- {
- int tmp;
- CBase baseObj;
- //baseObj.a_base_private = 1; // KO, 对象不能访问类的 private 成员
- //baseObj.b_base_protected = 1; // KO, 对象不能访问类的 protected 成员
- baseObj.c_base_public = 1; // OK, 对象可以访问类的 public 成员
- tmp = baseObj.getA(); // OK, 对象可以访问类的 public 成员
- tmp = baseObj.getB(); // OK, 对象可以访问类的 public 成员
- tmp = baseObj.getC(); // OK, 对象可以访问类的 public 成员
- }
从以上实践中可以得出以下结论:
类可以访问自身的所有成员, 不论是 private, protected 还是 public.
对象只能访问类的 public 成员.
友元的访问权限
在以上例子的基础上, 让我们来考虑一下, 对于该类中被不同访问控制修饰符修饰的成员, 该类的友元函数和友元类对这些成员都有什么样的访问权限.
- #include <iostream>
- using namespace std;
- class CBase;
- class CFriend;
- void ClearBaseA(CBase &obj);
- class CBase
- {
- friend CFriend; // 声明 CFriend 为自己的友元类
- friend void ClearBaseB(CBase &obj); // 声明 ClearBaseA 为自己的友元函数
- private:
- int a_base_private;
- protected:
- int b_base_protected;
- public:
- int c_base_public;
- public:
- CBase(){a_base_private = 1; b_base_protected = 2; c_base_public = 3;}
- ~CBase(){}
- int getA() const {return a_base_private;} // OK, 类可以访问自身的所有成员
- int getB() const {return b_base_protected;} // OK, 类可以访问自身的所有成员
- int getC() const {return c_base_public;} // OK, 类可以访问自身的所有成员
- };
- class CFriend
- {
- private:
- CBase obj;
- public:
- CFriend(){}
- ~CFriend(){}
- int setBaseA(int f) {obj.a_base_private = f;} // OK, 在友元类中, 可以访问 Base 类的私有成员
- int getBaseA() const {return obj.getA();}
- };
- void ClearBaseB(CBase &obj)
- {
- obj.b_base_protected = 0; // OK, 在友元函数中, 可以访问 Base 类的保护成员
- }
- int main()
- {
- int tmp;
- CBase baseObj;
- CFriend friendObj;
- cout <<baseObj.getB() << endl; // 通过构造函数初始化为 2
- ClearBaseB(baseObj);
- cout << baseObj.getB() << endl; // 被友元函数给清 0 了
- cout << friendObj.getBaseA() << endl; // 通过构造函数初始化为 1
- friendObj.setBaseA(7);
- cout << friendObj.getBaseA() << endl; // 被友元类给设置为了 7
- }
由上例中可以看出, 友元可以访问类中的 private 和 protected 成员, 对于 public 成员, 当然更是可以访问的了, 虽然以上例子中并没有验证这一点.
所以, 我们可以得出以下结论:
友元函数或友元类可以访问类中的所有成员.
小结
我们换一个角度, 通过以下表格总结一下.
访问控制修饰符 | 类 | 对象 | 友元 |
---|---|---|---|
public | 可访问 | 可访问 | 可访问 |
protected | 可访问 | 不可访问 | 可访问 |
private | 可访问 | 不可访问 | 可访问 |
引入三种继承方式
在 C++ 中, 在继承的过程中, 有以下三种继承方式, 它们分别是:
- public (公有继承)
- protected (保护继承)
- private (私有继承)
这三个关键字与之前的三种访问控制修饰符刚好相同, 但在这里, 它们有不同的意义.
对于 public 继承, 基类中的成员的访问控制修饰符不作任何改动, 原样继承到派生类中.
也就是说, 基类中的 public 成员, 到了派生类中, 仍然是派生类的 public 成员; 基类中的 protected 成员, 到了派生类中, 仍然是 protected 成员; 基类中的 private 成员, 它对派生类不可见.
对于 protected 继承, 基类中的 public 成员, 在派生类中被派生为 protected 成员; 基类中的 protected 成员, 在派生类中仍然是 protected 成员; 基类中的 private 成员, 在派生类不可见.
对于 private 继承, 基类中的 public 和 protected 成员, 在派生类中, 均被派生为了 private 成员; 而基类中的 private 成员, 对派生类不可见.
public 继承方式
在第一个例子的基础之上, 我们通过 public 方式继承出一个新的派生类.
- #include <iostream>
- using namespace std;
- class CBase
- {
- private:
- int a_base_private;
- protected:
- int b_base_protected;
- public:
- int c_base_public;
- public:
- CBase(){a_base_private = 1; b_base_protected = 2; c_base_public = 3;}
- ~CBase(){}
- int getA() const {return a_base_private;} // OK, 类可以访问自身的所有成员
- int getB() const {return b_base_protected;} // OK, 类可以访问自身的所有成员
- int getC() const {return c_base_public;} // OK, 类可以访问自身的所有成员
- };
- class CDerived:public CBase
- {
- private:
- int x_derived_private;
- protected:
- int y_derived_protected;
- public:
- int z_derived_private;
- public:
- CDerived(){x_derived_private = 4; y_derived_protected = 5; z_derived_private = 6;}
- ~CDerived(){}
- //void setBaseA(int t){a_base_private = t;} // KO, 派生类中不能访问基类的 private 成员
- void setBaseB(int t){b_base_protected = t;} // OK, 派生类中可以访问基类的 protected 成员
- void setBaseC(int t){c_base_public = t;} // OK, 派生类中可以访问基类的 public 成员
- int getX() const {return x_derived_private;}
- int getY() const {return y_derived_protected;}
- int getZ() const {return z_derived_private;}
- };
- int main()
- {
- CDerived derivedObj;
- //derivedObj.a_base_private = 1; // KO, 基类中由 private 修饰的 a_base_private, 对派生类是不可见的, 即使在派生类中都不能访问, 更别提派生类对象了.
- //derivedObj.b_base_protected = 1; // KO, 对象不能访问类的 protected 成员 (public 方式继承的 protected 成员, 在派生类中仍为 protected 成员)
- derivedObj.c_base_public = 1; // OK, 对象可以访问类的 public 成员 (public 方式继承的 public 成员, 在派生类中仍为 public 成员)
- cout <<derivedObj.getA() << endl; // OK, 对象可以访问类的 public 成员 (public 方式继承的 public 成员, 在派生类中仍为 public 成员)
- derivedObj.setBaseB(8); // OK, 对象可以访问类的 public 成员
- cout << derivedObj.getB() << endl; // OK, 对象可以访问类的 public 成员 (public 方式继承的 public 成员, 在派生类中仍为 public 成员)
- derivedObj.setBaseC(9); // OK, 对象可以访问类的 public 成员
- cout << derivedObj.getC() << endl; // OK, 对象可以访问类的 public 成员 (public 方式继承的 public 成员, 在派生类中仍为 public 成员)
- }
由以上例子可以看出:
基类中的 private, protected, public 成员, 经由 public 继承之后, 在派生类中分别为不可见 private, protected,public 成员.
派生类中不能访问基类的 private 成员, 但可以访问基类的 private 和 protected 成员.
protected 继承方式
在第一个例子的基础之上, 我们通过 protected 方式继承出一个新的派生类.
- #include <iostream>
- using namespace std;
- class CBase
- {
- private:
- int a_base_private;
- protected:
- int b_base_protected;
- public:
- int c_base_public;
- public:
- CBase(){a_base_private = 1; b_base_protected = 2; c_base_public = 3;}
- ~CBase(){}
- int getA() const {return a_base_private;} // OK, 类可以访问自身的所有成员
- int getB() const {return b_base_protected;} // OK, 类可以访问自身的所有成员
- int getC() const {return c_base_public;} // OK, 类可以访问自身的所有成员
- };
- class CDerived:protected CBase
- {
- private:
- int x_derived_private;
- protected:
- int y_derived_protected;
- public:
- int z_derived_private;
- public:
- CDerived(){x_derived_private = 4; y_derived_protected = 5; z_derived_private = 6;}
- ~CDerived(){}
- //void setBaseA(int t){a_base_private = t;} // KO, 派生类中不能访问基类的 private 成员
- void setBaseB(int t){b_base_protected = t;} // OK, 派生类中可以访问基类的 protected 成员
- void setBaseC(int t){c_base_public = t;} // OK, 派生类中可以访问基类的 public 成员
- int getX() const {return x_derived_private;} // OK, 类可以访问自身的所有成员
- int getY() const {return y_derived_protected;} // OK, 类可以访问自身的所有成员
- int getZ() const {return z_derived_private;} // OK, 类可以访问自身的所有成员
- };
- int main()
- {
- CDerived derivedObj;
- //derivedObj.a_base_private = 1; // KO, 对象不能访问类的 private 成员 (protected 方式继承的 private 成员, 在派生类中不可见)
- //derivedObj.b_base_protected = 1; // KO, 对象不能访问类的 protected 成员 (protected 方式继承的 protected 成员, 在派生类中仍为 protected 成员)
- //derivedObj.c_base_public = 1; // KO, 对象不可以访问类的 protected 成员 (protected 方式继承的 public 成员, 在派生类中成为 protected 成员)
- //cout <<derivedObj.getA() << endl; // KO, 对象不可以访问类的 protected 成员 (protected 方式继承的 public 成员, 在派生类中成为 protected 成员)
- //cout << derivedObj.getB() << endl; // KO, 对象不可以访问类的 protected 成员 (protected 方式继承的 public 成员, 在派生类中成为 protected 成员)
- //cout << derivedObj.getC() << endl; // KO, 对象不可以访问类的 protected 成员 (protected 方式继承的 public 成员, 在派生类中成为 protected 成员)
- }
由以上例子可以看出:
基类中的 private, protected, public 成员, 经由 protected 继承之后, 在派生类中分别为不可见 private, protected,protected 成员.
派生类中不能访问基类的 private 成员, 但可以访问基类的 private 和 protected 成员.
private 继承方式
在第一个例子的基础之上, 我们通过 private 方式继承出一个新的派生类.
- #include <iostream>
- using namespace std;
- class CBase
- {
- private:
- int a_base_private;
- protected:
- int b_base_protected;
- public:
- int c_base_public;
- public:
- CBase(){a_base_private = 1; b_base_protected = 2; c_base_public = 3;}
- ~CBase(){}
- int getA() const {return a_base_private;} // OK, 类可以访问自身的所有成员
- int getB() const {return b_base_protected;} // OK, 类可以访问自身的所有成员
- int getC() const {return c_base_public;} // OK, 类可以访问自身的所有成员
- };
- class CDerived:private CBase
- {
- private:
- int x_derived_private;
- protected:
- int y_derived_protected;
- public:
- int z_derived_private;
- public:
- CDerived(){x_derived_private = 4; y_derived_protected = 5; z_derived_private = 6;}
- ~CDerived(){}
- //void setBaseA(int t){a_base_private = t;} // KO, 派生类中不能访问基类的 private 成员, 因为其在派生类中不可见
- void setBaseB(int t){b_base_protected = t;} // OK, 派生类中可以访问基类的 protected 成员
- void setBaseC(int t){c_base_public = t;} // OK, 派生类中可以访问基类的 public 成员
- int getX() const {return x_derived_private;} // OK, 类可以访问自身的所有成员
- int getY() const {return y_derived_protected;} // OK, 类可以访问自身的所有成员
- int getZ() const {return z_derived_private;} // OK, 类可以访问自身的所有成员
- };
- int main()
- {
- CDerived derivedObj;
- //derivedObj.a_base_private = 1; // KO, (private 方式继承的 private 成员, 在派生类中不可见)
- //derivedObj.b_base_protected = 1; // KO, (private 方式继承的 protected 成员, 在派生类中不可见)
- //derivedObj.c_base_public = 1; // KO, (private 方式继承的 public 成员, 在派生类中成为不可见)
- //cout << derivedObj.getA() << endl; // KO, (private 方式继承的 public 成员, 在派生类中不可见)
- //cout << derivedObj.getB() << endl; // KO, (private 方式继承的 public 成员, 在派生类中不可见)
- //cout << derivedObj.getC() << endl; // KO, (private 方式继承的 public 成员, 在派生类中不可见)
- cout << derivedObj.getX() << endl;
- cout << derivedObj.getY() << endl;
- cout << derivedObj.getZ() << endl;
- }
由以上例子可以看出:
基类中的 private, protected, public 成员, 经由 private 继承之后, 在派生类中均不可见.
派生类中不能访问基类的 private 成员, 但可以访问基类的 private 和 protected 成员.
小结
不论何种继承方式, 派生类都不能访问基类的 private 成员, 它只能访问基类的 public 和 protected 成员.
三种继承方式对不同访问控制符修饰的成员的影响如下表所示.
访问控制修饰符 | public 继承 | protected 继承 | private 继承 |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | private | private | private |
总结
友元和类一样, 可以访问类的所有成员.
对象只能访问类的 public 成员.
派生类只能访问基类的 public 和 protected 成员, 而不能访问基类的 private 成员.
对于派生出来的类, 首先根据继承方式, 确定基类各成员在经指定的继承方式继承后的访问控制权限 (经继承后基类各成员是变成了 public,protected 还是 private), 然后根据第 1,2,3 点对各成员进行访问.
经继承后, 基类中的成员会根据继承方式, 对各成员的访问控制符进行修改. 修改之后, 基类中的 private 成员对派生类不可见.
来源: https://www.cnblogs.com/outs/p/10128993.html