相同的层次结构,访问基 class 的受保护成员时的不同行为

Same hierarchy, different behaviour when accessing protected member of base class

我在过去的考试中遇到过这段代码:

#include <iostream>
class cls1
{
protected:
    int x;

public:
    cls1()
    {
        x = 13;
    }
};
class cls2 : public cls1
{
    int y;

public:
    cls2()
    {
        y = 15;
    }
    int f(cls2 ob)
    {
        return (ob.x + ob.y);
    }
};
int main()
{
    cls2 ob;
    std::cout << ob.f(ob);
    return 0;
}

这工作正常并输出 28。问题是,它似乎与这段代码相矛盾(在另一次考试中发现):

#include <iostream>
class B
{
protected:
    int x;

public:
    B(int i = 28)
    {
        x = i;
    }
    virtual B f(B ob)
    {
        return x + ob.x + 1;
    }
    void afisare()
    {
        std::cout << x;
    }
};
class D : public B
{
public:
    D(int i = -32)
        : B(i)
    {
    }
    B f(B ob)
    {
        return x + ob.x - 1;/// int B::x is protected within this context
    }
};
int main()
{
    B *p1 = new D, *p2 = new B, *p3 = new B(p1->f(*p2));
    p3->afisare();
    return 0;
}

这是同一类型的层次结构,但一个可以访问 ob.x 而另一个不能。有人可以向我解释这是为什么吗?

不同之处在于,在第一种情况下,protected 成员是通过派生的 class 访问的。在第二种情况下,protected 成员是通过基础 class 访问的,这是不允许的。

对于protected members,

(强调我的)

A protected member of a class is only accessible

2) to the members and friends (until C++17) of any derived class of that class, but only when the class of the object through which the protected member is accessed is that derived class or a derived class of that derived class:

struct Base {
  protected:
    int i;
  private:
    void g(Base& b, struct Derived& d);
};

struct Derived : Base {
  void f(Base& b, Derived& d) { // member function of a derived class
    ++d.i;                      // OK: the type of d is Derived
    ++i;                        // OK: the type of the implied '*this' is Derived
//  ++b.i;                      // error: can't access a protected member through
                                // Base (otherwise it would be possible to change
                                // other derived classes, like a hypothetical
                                // Derived2, base implementation)
  }
};