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

Why can't a derived class call protected member function in this code?

本文关键字:受保护 调用 成员 函数 代码 派生 不能 为什么      更新时间:2023-10-16
#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的受保护成员可以使用,而其他实例的受保护成员永远无法访问。

但:

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++编程一段时间了,但我找不到任何解释这个行为。

编辑:

无论它是相同的还是不同的实例:

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

EDIT2:

似乎当涉及到访问权限时,使用类的实例根本无关紧要:

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

尽管c++中的访问控制是基于类的(而不是基于实例的),但protected访问说明符有一些特殊之处。

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

由于这个原因,您必须通过pointer->member语法,reference.memberobject.member语法访问受保护的成员,其中指针/引用/对象指向派生的类。

这意味着在你的例子中,受保护成员somethingProtected()不能通过Base对象、Base *指针或Base &引用访问,但可以通过Derived对象、Derived *指针和Derived &引用访问。您的普通somethingProtected()访问是允许的,因为它只是this->somethingProtected()的简写,其中thisDerived *类型。

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

注意,按照上述规则在

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

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

我相信您对如何访问基类成员有一些困惑。只有这样:

class Derived : public Base
void drivedMethod() {
    Base::baseMethod();
}

在你的例子中,你试图访问另一个实例的受保护成员。

派生实例可以访问它自己的受保护成员,但不能访问其他类实例受保护的成员,这是设计的。

实际上访问另一个类的受保护成员,从另一个实例成员或从main函数实际上都是在公共访问下…

http://www.cplusplus.com/doc/tutorial/inheritance/(查找访问说明符表以查看不同级别)

两个例子证明了同样的事情,例如:

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

这里你的派生类得到b作为参数,所以它得到另一个基的实例,然后因为b. somethingprotected不是公共的,它不会完成。

这将完成:

void somethingDerived()
{
   Base::somethingDerived();

你的第二个例子很好,因为你正在访问另一个d类的公共方法

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

Derived类只能访问Derived对象中受保护的基成员。它不能访问非(必须)Derived对象中的成员。在失败的情况下,您尝试通过Base &访问成员,并且由于这可能引用的对象不是Derived,因此无法进行访问。

你所做的在c++中是非法的。类的对象不能访问受保护的成员。只有成员函数可以访问受保护的成员。protected成员的行为就像私有成员一样,除了被派生类继承。考虑下面给出的程序来理解私有成员、公共成员和受保护成员之间的区别。

class Base
{
    private:
    void somethingPrivate()
    {
        std::cout << "sasa" << std::endl;
    }
    public:
    void somethingPublic()
    {
        std::cout << "haha" << std::endl;
    }
    protected:
    void somethingProtected()
    {
        std::cout << "lala" << std::endl;
    }
};
class Derived : public Base
{
public:
    void somethingDerived()
    {
       Base b;
       b.somethingPublic();   // Works fine.
       somethingProtected();  // This is also fine because accessed by member function.
       //b.somethingProtected();  // Error. Called using object b.
       //somethingPrivate();      // Error. The function is not inherited by Derived.
    }
};