c++ - 深入了解 C++ protected

标签 c++ protected

2011 C++ Standard states在第 11.4 节中

An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class ( 11.2 ) 115 As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C . If the access is to form a pointer to member ( 5.3.1 ), the nested-name-specifier shall denote C or a class derived from C . All other accesses involve a (possibly implicit) object expression ( 5.2.5 ). In this case, the class of the object expression shall be C or a class derived from C .

(在旧标准中,类似的措辞在第 11.5 节中。)

这条规则限制了“B 的 protected 成员可以被任何 B 或 B 的派生类访问”这一经常重复的想法。然而,解释该规则很困难,当前不同的编译器以不同方式执行该规则这一事实证明了这一点。

例如,请参阅此测试代码。我使用 Apple LLVM Compiler 4.1、GCC 4.7.2 和 Visual Studio 2010 编译了这段代码。它们报告的错误既有相似之处,也有不同之处。

class Base
{
protected:
    int A;
};

class Derived : public Base
{
protected:
    int B;
};

class Grandchild : public Derived
{
    void access_protected(Base* b, Derived* d,
                          Grandchild* g, class GreatGrandchild* gg );
};

class GreatGrandchild : public Grandchild {};

void Grandchild::access_protected(Base* b, Derived* d,
                                  Grandchild* g, GreatGrandchild* gg )
{
    int* p;

    Base lb;
    Derived ld;
    Grandchild lg;
    GreatGrandchild lgg;

    A = 1;              // Legal...
    B = 2;

    Base::A = 1;
    Derived::B = 2;

    b->A = 1;           // Illegal ALL
    p = &(b->A);        // Illegal ALL
    lb.A = 1;           // Illegal ALL
    p = &(lb.A);        // Illegal ALL

    d->A = 1;           // Illegal GCC, VS
    p = &(d->A);        // Illegal GCC, VS
    ld.A = 1;           // Illegal GCC, VS
    p = &(ld.A);        // Illegal GCC, VS
    d->B = 2;           // Illegal ALL
    p = &(d->B);        // Illegal ALL
    ld.B = 2;           // Illegal ALL
    p = &(ld.B);        // Illegal ALL

    g->A = 1;           // Legal...
    g->B = 2;
    lg.A = 1;
    lg.B = 2;

    gg->A = 1;
    gg->B = 2;
    lgg.A = 1;
    lgg.B = 2;
}

从这些结果中我了解到:(1) 访问您自己的类和派生类的 protected 成员总是可以的; (2) 访问声明它们的基类的 protected 成员始终是非法的,但该类除外; (3) 尽管标准注意区分指向成员的指针和“对象表达式”,但标准和编译器都给予它们相同的限制; (4) 尚不清楚访问“中间”基类(示例中的 Derived)的 protected 成员是否合法,该成员是在中间基类中声明的。

然后,我是否可以谈论我祖 parent 的 protected 成员归我 parent 所有,这让我感到困惑。没有双关语。

(为了简单和理智起见,我忽略了 friend 。)

由于 protected 是该语言的基础部分,我有动力好好理解它。请:

  1. 根据您对标准的解释,哪个编译器正确实现了这一点?
  2. 整体限制的理由是什么?为什么我不能自由访问基类的 protected 成员?它旨在避免什么具体错误?您是否知道探索此基本原理的在线讨论(最好由标准委员会举行)?

最佳答案

我会说 GCC 和 Visual Studio 是正确的。

鉴于以下情况:

class Base
{
protected:
  int A;
};

class Derived : public Base
{
protected:
  int B;
};

class OtherGrandchild : Derived
{
};

class Grandchild : Derived
{
  void access_protected(OtherGrandchild* otherGrandchild);
};

void Grandchild::access_protected(OtherGrandchild* otherGrandchild)
{
  otherGrandchild->A = 1; // Should be illegal
  otherGrandchild->B = 1; // Should be illegal

  Derived* derived = static_cast<Derived*>(otherGrandchild);

  derived->A = 1; // Should still be illegal
  derived->B = 1; // Should still be illegal
}

如果您不受限制,您可以将 OtherGrandchild 的其他私有(private)成员从 Grandchild 转换为公共(public)基类型。只能通过 friend 声明允许这种访问。

我不确定关于该主题的任何讨论,但这将是我对此的解释。

关于c++ - 深入了解 C++ protected ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14524278/

相关文章:

java - JUnit 测试 : invoking parent class protected method

java - 在不使用 protected 的情况下处理抽象类的正确方法是什么?

memory - 单击 CrViewer 打印按钮时出现 "Attempted to read or write protected memory.."错误

c++ - Visual Studio 2017 : Cannot open include file 'd3dx9.h' no such file or directory in a static library used by . exe 应用程序

c++ - 使用 cmake 构建 Qt 4 项目时出错

c++ - 一个大的 OpenGL 顶点缓冲区,还是许多小的?

c++ - "Identifier is undefined"访问子类中的"protected"数据时出错

ASP.NET - protected 变量

c++ - 我可以在不安装可分发的 VC++ 程序包的情况下将 MSVCRT DLL 与我的应用程序捆绑在一起吗

c++ - 十进制包括负到 32 位二进制转换器