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

时间:2013-05-28 06:17:07

标签: c++ oop

#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;
};

4 个答案:

答案 0 :(得分:72)

即使C ++中的访问控制依赖于每个类(而不是基于每个实例),protected访问说明符也有一些特殊性。

语言规范要确保您正在访问属于派生类的某些基础子对象的受保护成员。您不应该能够访问某些不相关的基类型独立对象的受保护成员。特别是,您无法访问基本类型的独立对象的受保护成员。您只能将 embedded 的基础对象的受保护成员作为基础子对象访问到派生对象中。

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

这意味着在您的示例中,受保护的成员somethingProtected()无法通过Base个对象,Base *指针或Base &引用访问,但可以通过{{1对象,Derived指针和Derived *引用。您可以使用Derived &访问权限,因为它只是somethingProtected()的简写,其中this->somethingProtected()的类型为this

Derived *违反了上述要求。

注意按照上述规则

b.somethingProtected()

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

答案 1 :(得分:3)

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

class Derived : public Base
void drivedMethod() {
    Base::baseMethod();
}
在您的示例中,您尝试访问另一个实例的受保护成员。

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

事实上,从另一个实例成员或主函数访问另一个类的受保护成员实际上都是公共访问...

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

两个例子都证明了相同的例子:

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

这里你的Derived类将b作为一个参数,所以它得到了另一个base实例,那么因为b.somethingProtected不是公共的,所以它不会编译..

这将成为:

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

你的第二个例子符合要求,因为你正在访问另一个d类的公共方法

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

你所做的是在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.
    }
};