我试图完全理解C++标准[class.access]部分的多个段落中定义的成员访问规则。它们相当complex or even confusing,因此我需要一个简短但准确而详尽的摘要。
我编译了该程序,以测试几种情况下 protected 成员的可访问性(因为 protected 成员的规则最复杂):1

#include <iostream>

class B {
  protected:
    int i = 1;
    static int const I = 1;
};

class X: public B {
  protected:
    int j = 2;
    static int const J = 2;
  public:
    void f();
    friend void g();
};

class D: public X {
  protected:
    int k = 3;
    static int const K = 3;
};

void X::f() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  std::cout << b.I;
  std::cout << x.i;
  std::cout << x.I;
  std::cout << x.j;
  std::cout << x.J;
  std::cout << d.i;
  std::cout << d.I;
  std::cout << d.j;
  std::cout << d.J;
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
}

void g() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  //std::cout << b.I;  // error: 'I' is a protected member of 'B'
  std::cout << x.i;
  std::cout << x.I;
  std::cout << x.j;
  std::cout << x.J;
  std::cout << d.i;
  std::cout << d.I;
  std::cout << d.j;
  std::cout << d.J;
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
}

int main() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  //std::cout << b.I;  // error: 'I' is a protected member of 'B'
  //std::cout << x.i;  // error: 'i' is a protected member of 'B'
  //std::cout << x.I;  // error: 'I' is a protected member of 'B'
  //std::cout << x.j;  // error: 'j' is a protected member of 'X'
  //std::cout << x.J;  // error: 'J' is a protected member of 'X'
  //std::cout << d.i;  // error: 'i' is a protected member of 'B'
  //std::cout << d.I;  // error: 'I' is a protected member of 'B'
  //std::cout << d.j;  // error: 'j' is a protected member of 'X'
  //std::cout << d.J;  // error: 'J' is a protected member of 'X'
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
  return 0;
}
我得出有关直接可及性的结论:2
  • 类的公共(public)成员可直接由任何实体访问(请参阅[class.access/base-5.1]);
  • 类(class)的私有(private)成员仅可直接由该类(class)的成员和 friend 访问(参见[class.access/base-5.2]);
  • 类的 protected 成员只有该类的成员和 friend (请参阅[class.access/base-5.3])可以直接访问该类的成员和 friend (如果这些 protected 成员是从那些基类或基类继承的,则该类的基类的成员和 friend 可以直接访问)如果这些 protected 成员既不是非静态数据成员也不是非静态成员函数(参见[class.access/base-5.4]),则将这些基类(参见[class.access/base-5.3])中的3,以及该类的派生类的成员(参见[class.access/class.protected-1])。

  • 我的总结正确吗?

    1我在C++ 17中使用了Clang 9.0.0编译器。
    2对类i的成员B的访问可以是直接的,即通过该类:b.i(直接访问),也可以是间接的,即通过该类的派生类D:d.i(继承访问)。由于派生类继承的成员是该派生类的成员,且其可访问性发生了变化(参见[class.access/base-1]),因此对类成员的继承访问可以视为对该类派生类的继承成员的直接访问。换句话说,只需要考虑直接访问。
    3这里的My子句与标准[class.access/base-5.4]的引用子句略有不同:

    这是因为编译器的行为有所不同,我的感觉是编译器是正确的。我认为该标准的条款存在两个问题:
  • ,访问点R应该限于B类的成员和 friend (这是编译器通过在程序的d.*中引发main访问的错误来完成的工作);
  • 应该限制类N中的成员m继承自类B,而不是被类N覆盖(这是编译器将通过在d.id.I中引发d.jd.JX::fg访问错误而完成的工作,在程序中的i中覆盖了IjJD)。
  • 最佳答案

    如果您的问题基于访问权限,则这些是c++中的规则。我将在下面做一个基本的总结,但是对于详尽的解释,请转到here。这将更详细地介绍它们的工作原理。



    要查看示例,请转到上面的链接。

    使用嵌套类,您将处于该基类的范围之内,因此可以访问私有(private)成员和 protected 成员。如果成员是静态的,则您将可以直接访问,否则必须构造该类的对象才能访问该类中的那些成员。这是上面class X的示例:

    class X: public B {
    public:
        class A {
        public:
            void b() {
                std::cout << J << std::endl;
                std::cout << S << std::endl;
            }
            void d(X x) {
                std::cout << x.j << std::endl;
                std::cout << x.s << std::endl;
            }
        };
    
        void f();
    
    protected:
        int j = 2;
        static int const J = 2;
    private:
        friend void g();
        int s = 3;
        static int const S = 4;
    };
    

    这是将它们用于继承时公开, protected 和私有(private)的含义。



    注意:派生类继承基类的所有方法,但以下情况除外。
  • 基类
  • 的构造函数,析构函数和拷贝构造函数
  • 重载了基类的运算符-这些运算符可能无法按您预期的方式运行,因此应以为每个类的每个运算符覆盖的方式实现。
  • 基类的 friend 功能。

  • 现在关于 friend 说明符,这来自cpp引用here
    在这里,您将获得示例以及有关如何使用它的详细说明。

    当涉及到标准库时,您还将在其中找到有关许多信息的示例,还可以了解将来的标准以及编译器支持的功能。

    08-25 08:13
    查看更多