摘要:本文是从饮水思源BBS C/C++版上一篇帖子引发的思考。当时看到帖子,突然觉得平时见惯了的,在这里似乎变得陌生了,究竟访问控制符怎样起作用,怎样使用,该怎样理解,本文试图给出讨论。

原帖如下

1 #include <IOSTREAM>
 2 using namespace std;
 3 
 4 class A{
 5 public:
 6     A(int i_,int j_)
 7     {
 8         i=i_;
 9         j=j_;
10     }
11     void disp(A &a)
12     {
13         cout<<a.i<<endl<<a.j<<endl;
14     }
15 
16 private:
17     int i;
18 protected:
19     int j;
20 };
21 
22 int main(int argc, char* argv[])
23 {
24     A a(123,456);
25     A b(789,543);
26     a.disp(b);
27     b.disp(a);
28 
29     return 0;
30 }

初看起来,倒是会产生疑问。为什么会这样,是否有bug?
仔细考究起来,我们其实可以这样看待类和对象:
类是将数据成员和进行于其上的一系列操作(成员函数)封装在一起,注意:成员函数可以操作数据成员(可以称类中的数据成员为泛数据成员)!
对象是类的实例化,怎样理解实例化?其实每一个实例对象都只是对其中的数据成员初始化,内存映像中每个对象仅仅保留属于自己的那份数据成员副本。而成员函数对于整个类而言却是共享的,即一个类只保留一份成员函数。
那么每个对象怎样和这些可以认为是“分离”的成员函数发生联系,即成员函数如何操作对象的数据成员?记住this指针,无论对象通过(.)操作或者(->)操作调用成员函数,编译时刻,编译器都会将这种调用转换成我们常见的全局函数的形式,并且多出一个参数(一般这个参数放在第一个),然后将this指针传入这个参数。于是就完成了对象与成员函数的绑定(或联系).
实例化后就得到同一个类的多个不同的对象,既然成员函数共享的,那么成员函数就可以操作对象的数据成员。
问题是现在有多个对象,成员函数需要知道操作的是哪个对象的数据成员?
比如有对象obj1和obj2,都属于A类,A类有public成员函数foo()
如果obj1调用该函数,编译时会给foo函数传入this指针,obj1,foo中操作obj1自身的成员就不用任何修饰,直接访问,因为其中的数据成员自动根据this指针找到。
如果obj1调用该函数,同样可以访问同类的其他对象的数据成员!那么你需要做的是让foo函数知道是同类对象中哪个对象的数据成员,一个解决办法是传入同类其他对象的指针或引用,那么就可以操作同类其他对象的数据成员。
foo(A &obj)
这样定义,然后调用:
obj1.foo(obj2)
就可以在obj1访问obj2的数据成员,而无论这些数据成员是private还是protected

搬出C++ Object Model,可以画出各个对象的内存map就可以更清晰的看出:

总结:C++的访问修饰符的作用是以类为单位,而不是以对象为单位。

通俗的讲,同类的对象间可以“互相访问”对方的数据成员,只不过访问途径不是直接访问.
步骤是:通过一个对象调用其public成员函数,此成员函数可以访问到自己的或者同类其他对象的public/private/protected数据成员和成员函数(类的所有对象共用),而且还需要指明是哪个对象的数据成员(调用函数的对象自己的成员不用指明,因为有this指针;其他对象的数据成员可以通过引用或指针间接指明)

C++中public,protected,private访问小结
第一:private,public,protected方法的访问范围.(public继承下)
private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.
protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问
public: 可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问
注:友元函数包括两种:设为友元的全局函数,设为友元类中的成员函数

第二:类的继承后方法属性变化:
使用private继承,父类的所有方法在子类中变为private;
使用protected继承,父类的protected和public方法在子类中变为protected,private方法不变;
使用public继承,父类中的方法属性不发生改变;

public: protected: private:
public继承 public protected ---
protected继承 protected protected ---
private继承 private private ---

protected继承和private继承能降低访问权限

再次提到:可以提供访问行为的主语为“函数”。
类体内的访问没有访问限制一说,即private函数可以访问public/protected/private成员函数或数据成员,同理,protected函数,public函数也可以任意访问该类体中定义的成员
public继承下,基类中的public和protected成员继承为该子类的public和protected成员(成员函数或数据成员),然后访问仍然按类内的无限制访问

对于类域范围内,成员函数访问无所谓访问限制。
对于继承情况下的基类private成员,在派生类中仍然继承了下来,只不过它不能直接访问,   即使在类里也不行,   更不用说是类对象了。
可以通过下列例子看到:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class C{
 5 public:
 6     C(int val) : m_c(val) {}
 7 private:
 8     int m_c;
 9 };
10 
11 class D: public C{
12 public:
13     D(int val1, int val2) : C(val1), m_d(val2) {}
14     int m_d;
15 };
16 
17 int main()
18 {
19 
20 
21     cout << sizeof(C) << " " << sizeof(D) << endl; // 4  8
22     D obj(2, 25);
23     cout << &obj << " " << &obj.m_d << endl; //0x0012FF78   0X0012FF7C
24     //cout << obj.m_c;  //error, 不能访问
25 
26     D *ptr = &obj;
27     int *iptr = (int *)ptr;
28     cout << *iptr << " " << *(iptr+1) << endl;//2  25
29     
30     return 0;
31 }
32 
33 

同样,加入虚函数,可以看到VC编译器将vptr放置在数据区的最开头

下面摘自博客园的一篇,相当精辟的理解:


下面这个问题摘自论坛的一个帖子:

已知3个类O、P和Q,类O中定义了一个私有方法F1、一个公有方法F2和一个受保护的方法F3:类P和类Q是类O的派生类,其继承方式如下所示:
class P : protected O {…};
class Q : public O {…};
关于方法F1的描述中正确的是___(34)___;关于方法F2韵描述中正确的是___(35)___;关于方法F3的描述中正确的是___(36)___。
(34)
A.方法F1无法被访问
B.只有在类O内才能访问方法F1
C.只有在类P内才能访问方法F1
D.只有在类Q内才能访问方法F1
(35)
A.类O、P和Q的对象都可以访问方法F2
B.类P和Q的对象都可以访问方法F2
C.类0和Q的对象都可以访问方法F2
 D.只有在类P内才能访问方法F2
(36)A.类0、P和Q的对象都可以访问方法F3
B.类0、P和Q的对象都不可以访问方法F3
C.类0和Q的对象都可以访问方法F3
D.类P和Q的对象都可以访问方法F3。

有甚么办法可以简单地记住这许多的规则? 下文告诉你一个根本不需要记的办法。

顾名思义,private/public/protected 分别表示 私有/公开/保护,它们是一组用于访问权限控制的关键字。那么首先,需要澄清的一个关键点是,是要控制谁访问谁的权限?这个访问的主语(施事)是谁?宾语(受事)是谁?

我们经常听到这样的说法:

1)一个类友元可以访问该类的任何成员(包括成员变量及成员方法,下同)。
2)private成员只有该类自身可以访问,protected成员只有该类及其派生类可以访问,public成员所有的人都可以访问。

宾语(受事)是谁这一点很明确,是类的成员(包括成员变量及成员方法)。主语(施事)是谁?这是让大家发生混淆的关键点。也是这个说法中含糊不清的地方。

想清楚一点,其实主语(施事)指的是一个函数,而不是(当然更不是变量)。private/public/protected要控制的是一个函数(施事)对一个类的成员(包括成员变量及成员方法)的访问权限。因此比较完整的说法是:

1)一个类友元(包含友元函数或者友元类的所有成员函数)可以访问该类的任何成员(包括成员变量及成员方法)。

2)除去友元外,private成员只有该类自身的成员函数可以访问,protected成员只有该类的成员函数及其派生类的成员函数可以访问,public成员则所有的函数都可以访问。

也就是说,当我们说一个类可以访问XXX,其实暗指这个类的成员函数可以访问XXX。了解了这一点,外加一条显而易见的规则,上面的问题就不难回答了。这条规则是:

3)派生类在继承时可削弱成员的访问权限(通过protected/private修饰)。例如上面的例子class P : protected O {…}; 那么某个函数通过类P访问O中成员时,该函数对类O中的public成员只有protected权限。

补充:有一种技术叫Member Spy(类成员间谍),通过该技术派生类可将基类的protected成员修改为public权限。这种技术用到了using关键字。举例如下:

class A
{
protected:
 int m_data;
};

class SpyA : public A
{
public:
 using A::m_data;
};

void TestSpy(A* pA)
{
 SpyA* pSpyA = static_cast<SpyA*>(pA);
 // 强制转换A为SpyA,这要求SpyA没有成员变量且没有重载A中的虚函数。
 // 现在你可以通过pSpyA访问m_data了。例如:int data = pSpyA->m_data;
}

由于这种技术用到了强制类型转换,当谨慎使用。



题目:自己定义一个class,它只有一个数据成员,且为private, 其成员函数都为public, 它生成两个对象obj1, obj2, 先要求用最少的成员函数实现obj1访问obj2的private数据成员。

实现一:

C++ 类访问控制public/private/protected探讨相关推荐

  1. php中public放什么,PHP中常用关键字public, private, protected, static...

    PHP中常用的关键字:public, private, protected, static, interface, implements, final 1.public.protected.priva ...

  2. 深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

    访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类.类成员函数.类成员变量进行访问控制.同时,访问控制符也是语法保留关键字,用于封装组件. Public, Private, Protec ...

  3. java访问权限 public private protected

    作者:yan 1. Java中的访问控制 表1-1 可见/访问性 在同一类中 同一包中 不同包中  同一包子类中  不同包子类中   public  yes  yes  yes  yes  yes   ...

  4. public,private,protected访问权限在Java,C++中的解析

    Java中: Java中的访问权限有public,private,protected和默认的包访问权限,如果类中的属性方法没有显示的指明访问权限,则具有包访问权限,我喜欢称它为packeged权限,很 ...

  5. java面试题三十 public,private,protected,default访问权限

    1 考题描述: 2 答案 BD 3解析 B. no modifer既为default也就是friendly 3.1 public,private,protected,default访问权限图 3.2证 ...

  6. PHP Class中public,private,protected,static的区别

    PHP Class中public,private,protected,static的区别 public:权限是最大的,可以内部调用,实例调用,可以被继承. protected:受保护类型,用于本类和继 ...

  7. php class中public,private,protected的区别以及实例分析

    本篇文章是对php class中public,private,protected的区别以及实例进行了详细的分析介绍,需要的朋友参考下 一,public,private,protected的区别 pub ...

  8. public,private,protected,default详解

    [一]public,private,protected,default public 作用:可以被该类的和非该类的任何成员访问. 注意:使用public关键字声明的类必须与java文件名保持一致,并且 ...

  9. C++ 笔记(16)— 类和对象(类定义、类实例对象定义、访问类成员、类成员函数、类 public/private/protected 成员、类对象引用和指针)

    1. 类的定义 类定义是以关键字 class 开头,后跟类的名称.并在它后面依次包含类名,一组放在 {} 内的成员属性和成员函数,以及结尾的分号. 类声明将类本身及其属性告诉编译器.类声明本身并不能改 ...

最新文章

  1. 手机拍视频最怕抖,只能靠AI拯救了
  2. 七大Github机器学习热门项目
  3. 史迪仔的原型_星际宝贝三个版本对比,莉罗抛弃史迪仔,童年真的回不去了
  4. 接口传值后不起作用_前端工程师吐后端工程师(第八讲)——接口的开发
  5. HDU 1520Anniversary party(树型DP)
  6. 一套完整java项目 后台+管理+前端
  7. 标准C++ 与 VC++ 区别集锦(待续)
  8. Spring入门第六课
  9. WinRAR 4.00 beta1 简体中文版
  10. vue中headers是什么_vue在响应头response中获取自定义headers操作
  11. 车轱辘APP提交到各应用市场的心得~
  12. Zencart完美程序来了,首个Zencart模板引擎来了
  13. 企业级带库走向大型化、智能化
  14. 二叉树的先序创建、前中后序遍历(递归)C++
  15. 损失函数、梯度和学习率的理解及用python实现梯度下降法
  16. 如何有效建立触摸屏与PLC之间无线通讯?
  17. 含泪整理最优质天空ps后期素材素材,你想要的这里都有
  18. 手机设备身份识别码之IMEI
  19. PHP生成唯一邀请码
  20. 如何在2020年任意设备上刷入Nethunter

热门文章

  1. 基于visual Studio2013解决面试题之0410计算二进制中1的个数
  2. 实现库函数strlen和strcpy
  3. 《Effective C#中文版:改善C#程序的50种方法》简介
  4. 需求阶段如何书写Use Case
  5. 含有运算放大器的电阻电路
  6. LwIP之网络接口管理
  7. python如何安装pdfminer_|请教在python3中安装pdfminer.six的方法
  8. 全球领先的数据库!我用它直接让公司项目的性能提升了一半~
  9. Kafka中副本机制的设计和原理
  10. 又一批长事务,P0故障谁来背锅?