相比C语言,C++中通过class/struct来定义既包含数据,又包含行为的结构,从而支持了“对象”。现实世界中,一个人(一个对象)通常 拥有一些资产(数据),并且掌握某些技能(行为),并且这些资产和技能通常可以分为三类:

  1. 可以与任何人分享的
  2. 有限分享的,比如留给子孙后代的财产或本领
  3. 除了自己之外谁也不能用的,比如给自己留的棺材^_^

为了表达类似的概念,在C++中使用public、protected以及private,分别代表可任意分享的、有限分享的以及独享的。比现实世界稍微复杂些,在C++中这三个关键字不仅可以修饰类成员,还可以修饰类的继承关系。

当这三个关键字用在类成员时:

  1. class Base
  2. {
  3. public:
  4. void publicMethod()
  5. {
  6. cout << "Begin of " << __FUNCTION__ << endl;
  7. cout << "End of " << __FUNCTION__ << endl;
  8. }
  9.  
  10. static void staticPublicMethod(Base* obj)
  11. {
  12. // just call this class's static private method
  13. staticPrivateMethod(obj);
  14. }
  15.  
  16. int getProperty() { return property_; }
  17. protected:
  18. void protectedMethod()
  19. {
  20. cout << "Begin of " << __FUNCTION__ << endl;
  21. cout << "call publicMethod from protected method: " << endl;
  22. publicMethod();
  23. cout << "End of " << __FUNCTION__ << endl;
  24. }
  25. private:
  26. void privateMethod()
  27. {
  28. cout << "Begin of " << __FUNCTION__ << endl;
  29.  
  30. cout << "call publicMethod from private method: " << endl;
  31. publicMethod();
  32.  
  33. cout << "call protected method from private method: " << endl;
  34. protectedMethod();
  35.  
  36. cout << "End of " << __FUNCTION__ << endl;
  37. }
  38.  
  39. static void staticPrivateMethod(Base* obj)
  40. {
  41. // ok
  42. obj->publicMethod();
  43.  
  44. // ok
  45. obj->protectedMethod();
  46.  
  47. // ok
  48. obj->privateMethod();
  49. }
  50.  
  51. int property_;
  52. };
  53.  
  54. class Derived : public Base
  55. {
  56. public:
  57. void accessBase()
  58. {
  59. cout << "In Derived::" << __FUNCTION__ << ": " << endl;
  60. cout << "we can access Base's public method:" << endl;
  61. publicMethod();
  62.  
  63. cout << "we can access Base's protected method too: " << endl;
  64. protectedMethod();
  65.  
  66. cout << "but we can't access Base's private method!" << endl;
  67. // we will get a compile error if we try to call privateMethod: 'privateMethod' is a private member of 'Base'
  68. // privateMethod();
  69. }
  70.  
  71. static void staticDerivedMethod(Derived* obj)
  72. {
  73. // ok
  74. obj->protectedMethod();
  75.  
  76. // compile error: 'privateMethod' is a private member of 'Base'
  77. // obj->privateMethod();
  78. }
  79. };
  80.  
  81. int main()
  82. {
  83. Base obj;
  84. // ok
  85. obj.publicMethod();
  86.  
  87. // compile error: 'protectedMethod' is a protected member of 'Base'
  88. // obj.protectedMethod();
  89.  
  90. // compile error: 'privateMethod' is a private member of 'Base'
  91. // obj.privateMethod();
  92.  
  93. // ok
  94. Base::staticPublicMethod(&obj);
  95.  
  96. Derived dobj;
  97. // ok
  98. dobj.accessBase();
  99.  
  100. // ok
  101. Derived::staticDerivedMethod(&dobj);
  102. return 0;
  103. }

从上面的程序中,可以看出:

  1. 用public修饰的成员,既可以在其类内部使用(在privateMethod中调用),也可以在类外部通过类的实例来访问(main函数中调用obj.publicMethod())
  2. 用protected修饰的成员,能在该类内部或者其派生类(严格上说是非私有继承的派生类,下面会详细介绍)中使用(见privateMethod、accessBase以及staticDerivedMethod)
  3. 用private修饰的成员,仅能在该类内部使用,在类外部或者派生类中都不能使用。

注意:以上描述中的“使用”,指的是直接引用(如不能在Derived中直接调用privateMethod)。尽管不能直接引用,但是仍然可以通过其他方法来访问(虽然在 Derived中无法直接访问Base的property_,但通过getProperty(),我们仍然可以在需要的时候获取其值)。

除了可以修饰类成员,这三个关键字还可以修饰类的继承关系:

  1. class Base
  2. {
  3. public:
  4. void publicBaseMethod()
  5. {
  6. cout << __FUNCTION__ << endl;
  7. }
  8. protected:
  9. void protectedBaseMethod()
  10. {
  11. cout << __FUNCTION__ << endl;
  12. }
  13. private:
  14. void privateBaseMethod()
  15. {
  16. cout << __FUNCTION__ << endl;
  17. }
  18. };
  19.  
  20. // public inheritance, all Base's members remain the same scope
  21. class PublicDerived : public Base
  22. {
  23. public:
  24. void accessBase()
  25. {
  26. // ok
  27. publicBaseMethod();
  28.  
  29. // ok
  30. protectedBaseMethod();
  31.  
  32. // compile error: 'privateBaseMethod' is a private member of 'Base'
  33. // privateBaseMethod();
  34. }
  35. };
  36.  
  37. // protected inheritance, Base's public members will become protected in ProtectedDerived
  38. class ProtectedDerived : protected Base
  39. {
  40. public:
  41. void accessBase()
  42. {
  43. // ok
  44. publicBaseMethod();
  45.  
  46. // ok
  47. protectedBaseMethod();
  48.  
  49. // compile error: 'privateBaseMethod' is a private member of 'Base'
  50. // privateBaseMethod();
  51. }
  52. };
  53.  
  54. // private inheritance, Base's public and protected members will become private in PrivateDerived
  55. class PrivateDerived : private Base
  56. {
  57. public:
  58. void accessBase()
  59. {
  60. // ok
  61. publicBaseMethod();
  62.  
  63. // ok
  64. protectedBaseMethod();
  65.  
  66. // compile error: 'privateBaseMethod' is a private member of 'Base'
  67. // privateBaseMethod();
  68. }
  69. };
  70.  
  71. class SonOfPrivateDerived : public PrivateDerived
  72. {
  73. public:
  74. void accessParent()
  75. {
  76. // compile error: 'publicBaseMethod' is a private member of 'Base'
  77. // publicBaseMethod();
  78.  
  79. // compile error: 'protectedBaseMethod' is a private member of 'Base'
  80. // protectedBaseMethod();
  81.  
  82. // IMPORTANTE NOTE: why PrivateDerived can access publicBaseMethod and protectedBaseMethod,
  83. // although they are both private members of 'Base'???
  84.  
  85. // compile error: 'privateBaseMethod' is a private member of 'Base'
  86. // privateBaseMethod();
  87. }
  88. };
  89.  
  90. int main()
  91. {
  92. PublicDerived pubd;
  93. // ok
  94. pubd.publicBaseMethod();
  95.  
  96. // compile error: 'protectedBaseMethod' is a protected member of 'Base'
  97. // pubd.protectedBaseMethod();
  98.  
  99. // compile error: 'privateBaseMethod' is a private member of 'Base'
  100. // pubd.privateBaseMethod();
  101.  
  102. pubd.accessBase();
  103.  
  104. ProtectedDerived prod;
  105. // compile error: 'publicBaseMethod' is a protected member of 'Base',
  106. // NOTE: the Base's public members now become protected in ProtectedDerived's perspective
  107. // prod.publicBaseMethod();
  108.  
  109. // compile error: 'protectedBaseMethod' is a protected member of 'Base'
  110. // NOTE: The Base's protected members remain protected in ProtectedDerived's perspective
  111. // prod.protectedBaseMethod();
  112.  
  113. // compile error: 'privateBaseMethod' is a private member of 'Base'
  114. // NOTE: The Base's private members remain private in ProtectedDerived's perspective
  115. // prod.privateBaseMethod();
  116.  
  117. prod.accessBase();
  118.  
  119. PrivateDerived prid;
  120. // compile error: 'publicBaseMethod' is a private member of 'Base'
  121. // NOTE: publicBaseMethod now become private in PrivateDerived's perspective
  122. // prid.publicBaseMethod();
  123.  
  124. // compile error: 'protectedBaseMethod' is a private member of 'Base'
  125. // NOTE: protectedBaseMethod also become private in PrivateDerived's perspective
  126. // prid.protectedBaseMethod();
  127.  
  128. // compile error: 'privateBaseMethod' is a private member of 'Base'
  129. // prid.privateBaseMethod();
  130.  
  131. prid.accessBase();
  132.  
  133. SonOfPrivateDerived pubprid;
  134. // NOTE: check the comments in accessParent to get the point
  135. pubprid.accessParent();
  136.  
  137. return 0;
  138. }

根据以上程序,可以得出public、protected和private在修饰继承关系中的作用为:

  1. 当使用公有继承(public Base)时,派生类中看到的基类成员属性与基类中定义的一致,如示例程序中publicBaseMethod、protectedBaseMethod和privateBaseMethod仍然分别为public、protected和private
  2. 当使用保护继承(protected Base)时,派生类中看到的基类的成员属性与基类定义不一致,原来基类中的public成员在派生类中被认为是基类的protected成员了,如示例中无法通过ProtectedDerived类的实例在类外部调用publicBaseMethod
  3. 当使用私有继承(private Base)时,派生类中看到的基类成员属性同样与基类定义不一致,即原来基类中的public和protected成员在派生类中都被当成了private成员了,如示例中只能在PrivateDerived类内部调用publicBaseMethod和protectedBaseMethod
  4. 在私有继承中,尽管当在外部调用public或protected成员时,其出错信息(通过clang++编译得到的)都是“'xxx' is a private member of 'Base'”,事实上并非如此:在私有继承关系中,基类的public和protected成员并非被当做基类的私有成员了,而是被当做派生类的私有成员了。如果是被当做是基类的私有成员,那么PrivateDerived中是无法访问publicBaseMethod和protectedBaseMethod的;但实际上,从PrivateDerived中可以访问publicBaseMethod和protectedBaseMethod,而SonOfPrivateDerived中无法访问它们,因此publicBaseMethod和protectedBaseMethod应该是PrivateDerived的私有成员而非Base的私有成员。

Author: Rex Shen

Created: 2014-02-16 Sun 08:24

Emacs 24.3.1 (Org mode 8.2.5h)

Validate

C++中public、protected以及private的使用的更多相关文章

  1. java中public protected friendly private作用域

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  2. C++中public,protected,private派生类继承问题和访问权限问题

    C++中public,protected,private派生类继承问题和访问权限问题 当一个子类从父类继承时,父类的所有成员成为子类的成员,此时对父类成员的访问状态由继承时使用的继承限定符决定. 1. ...

  3. java中的 public protected friendly private

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  4. public,protected,friendly,private的访问权限

    请说出作用域public,private,protected,以及不写时的区别 这四个作用域的可见范围如下表所示. 说明:如果在修饰的元素上面没有写任何访问修饰符,则表示friendly. 作用域   ...

  5. java 修饰符的作用一(public protected default private 组)

    1.public protected default private 组 public 权限最大,同类,同包,不同包,同包子类父类之间,不同包子类父类之间都可以访问. java 默认的权限是defau ...

  6. Java访问权限修饰符public protected friendly private用法总结(转载好文Mark)

    首先声明:Java中,friendly这个修饰符并没有显式的声明,在成员变量和方法前什么修饰符也不用,默认的就是friendly.为了条理清晰,分三种不同情况来总结. 一 访问权限修饰符修饰成员变量和 ...

  7. Java学习笔记(4)----Public,Protected,Package,Private修饰符可见性

    Java修饰符类型(public,protected,private,friendly) public的类.类属变量及方法,包内及包外的任何类均可以访问:protected的类.类属变量及方法,包内的 ...

  8. 【java基础】(1)Java的权限修饰符(public,protected,default,private)

    访问权限修饰符权限从高到低排列是public  ,protected  ,default, private. 一.根据“是否是同包”.“是否是子类”分为4中情况+本类 5种情况 二.把 同包中的子类 ...

  9. java四种权限修饰符(public > protected > (default) > private)

    权限修饰符在哪里可以访问 (default) : 表示什么权限修饰符都不写 位置 public protected (default) private 同一个类 yes yes yes yes 同一个 ...

  10. 【转载】C++中public,protected,private访问

    第一:private, public, protected 访问标号的访问范围. 假如我们约定: 类内部-----指的是当前类类型的定义中,以及其成员函数的声明和定义中: 类外部-----指的是不在当 ...

随机推荐

  1. js 的各种排序算法 -- 待续

    链接 function quickSort(arr,l,r){ if(l < r){ var i = l, j = r, x = arr[i]; while(i<j){ while(i&l ...

  2. 常量池之字符串常量池String.intern()

    运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...

  3. 7-8 List Leaves(25 分)

    Given a tree, you are supposed to list all the leaves in the order of top down, and left to right. I ...

  4. 全面剖析Smarty缓存机制一[三种缓存方式]

    今天主要全面总结下Smarty模板引擎中强大的缓存机制,缓存机制有效减少了系统对服务器的压力,而这也是很多开发者喜欢Smarty的原因之一,由于篇幅较大,便于博友阅读,这篇文章将剖析Smarty缓存的 ...

  5. github之本地上传

    在打算上传到github之前需要在github上面首先创建一个项目(点击右上角“+”号,点击New repository):

  6. PLSQL在64位 win7/WIN8上运行(绿色版plsql、无需安装oracle客户端)

    一.准备需要的文件: 1.plsql文件绿色压缩包 2.oracle客户端文件绿色压缩包 二.设置PLSQL 运行plsql,不登陆进入plsql点“工具”-“首选项” 按照如图设置“ oracle主 ...

  7. SpringCloud初体验:四、API GateWay 服务网关

    网关服务很多,比如:Zuul.Kong.spring cloud gateway ……, 这里不纠结哪种性能好,本次体验是用的 spring cloud gateway 更多网关比较可以了解这篇文章: ...

  8. sdk manager 代理,解决下载速度慢的问题

    原文:http://blog.csdn.net/android_panda/article/details/18598883 地址:mirrors.neusoft.edu.cn 端口:80 要勾选:F ...

  9. Javaweb经典三层架构的演变

    1.Javaweb经历了三个时期 ①JSP Model1第一代 JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的 ...

  10. 【理论】python使用celery异步处理请求

    Flask中使用celery队列处理执行时间较长的请求. 一. 安装celery pip install celery flask redis 二. celery简介 Celery是个异步分布式任务队 ...