为什么派生类不能在这段代码中调用受保护的成员函数?

2021-12-12 00:00:00 oop c++
#include <iostream>

class Base
{  
protected:
    void somethingProtected()
    {
        std::cout << "lala" << std::endl;
    }
};

class Derived : public Base
{
public:
    void somethingDerived()
    {
        Base b;
        b.somethingProtected();    // This does not compile
        somethingProtected();      // But this is fine
    }
};

int main()
{
    Derived d;
    d.somethingDerived();
    return 0;
}

我想也许只有this的受保护成员可以使用,而其他实例的受保护成员永远无法访问.

I thought that maybe only the protected members of this can be used and protected members of other instances are forever unreachable.

但是:

class Derived : public Base
{
public:

    void somethingDerived(Derived& d)
    {
        d.somethingProtected();  // This compiles even though d is
                                 // potentially a different instance
    }

    void somethingDerived(Base& b)
    {
        b.somethingProtected();  // This does not
    }
};

我对此感到有点恶心,因为我已经用 C++ 编程了一段时间,但我找不到对这种行为的任何解释.

I feel kind of nauseated by this, since I have been programming in C++ for some time, but I could not find any explanation for this behaviour.

无论是相同的还是不同的实例都没有关系:

It doesn't matter if it is the same or a different instance:

int main()
{
    Derived d1, d2;          // Two different instances
    d1.somethingDerived(d2); // This compiles fine
    d1.somethingDerived(d1); // This compiles fine
    return 0;
}

编辑 2:

似乎在访问权限方面,使用类的什么实例根本无关紧要:

It seems that when it comes to access rights, it doesn't matter at all what instance of a class is being used:

class Base
{
public:
    void something(Base& b)  // Another instance
    {
        ++b.a;               // But can enter private members
    }

private:
    int a;
};

推荐答案

尽管 C++ 中的访问控制是基于每个类(而不是基于每个实例)的,protected 访问说明符具有一些特点.

Even though access control in C++ works on per-class basis (as opposed to per-instance basis), protected access specifier has some peculiarities.

语言规范希望确保您正在访问属于派生类的某个基本子对象的受保护成员.您不应该能够访问一些基本类型的不相关的独立对象的受保护成员.特别是,您不能访问基本类型的 freestanding 对象的受保护成员.您只能访问作为基础子对象嵌入到派生对象中的基础对象的受保护成员.

The language specification wants to ensure that you are accessing a protected member of some base subobject that belongs to the derived class. You are not supposed to be able access protected members of some unrelated independent objects of base type. In particular, you cannot access protected members of freestanding objects of base type. You are only allowed to access protected members of base objects that are embedded into derived objects as base subobjects.

因此,您必须通过pointer->member 语法、reference.memberobject.member 语法访问受保护的成员,其中指针/引用/对象指的是派生类.

For this reason, you have to access protected members through pointer->member syntax, reference.member or object.member syntax, where the pointer/reference/object refers to the derived class.

这意味着在您的示例中,无法通过 Base 对象、Base * 指针或 访问受保护成员 somethingProtected()基础 & 引用,但它可以通过 Derived 对象、Derived * 指针和 Derived & 引用访问.允许您的普通 somethingProtected() 访问,因为它只是 this->somethingProtected() 的简写,其中 this 的类型为 <代码>派生的*.

This means that in your example, protected member somethingProtected() is not accessible through Base objects, Base * pointers or Base & references, but it is accessible through Derived objects, Derived * pointers and Derived & references. Your plain somethingProtected() access is allowed, since it is just a shorthand for this->somethingProtected() where this is of type Derived *.

b.somethingProtected() 违反了上述要求.

注意按照上面的规则

void Derived::somethingDerived()
{
    Base *b = this;
    b->somethingProtected();    // ERROR
    this->somethingProtected(); // OK
}

第一个调用也会失败,而第二个调用会编译,即使两者都试图访问同一个实体.

the first call will also fail while the second one will compile, even though both are trying to access the same entity.

相关文章