web-dev-qa-db-ja.com

このコードで派生クラスが保護されたメンバー関数を呼び出せないのはなぜですか?

#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:

アクセス権に関しては、クラスのinstanceが使用されているかどうかはまったく関係ないようです:

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

private:
    int a;
};
63
Martin Drozdik

C++のアクセス制御は(インスタンスごとではなく)クラスごとに機能しますが、protectedアクセス指定子にはいくつかの特性があります。

言語仕様では、派生クラスに属するいくつかのbaseサブオブジェクトの保護されたメンバーにアクセスしていることを確認する必要があります。基本型の関連のない独立したオブジェクトの保護されたメンバーにアクセスすることはできません。特に、ベース型のfreestandingオブジェクトの保護されたメンバーにはアクセスできません。派生オブジェクトにembeddedであるベースオブジェクトの保護されたメンバーにのみアクセスできます。

このため、pointer->member構文、reference.memberまたはobject.member構文を介して保護されたメンバーにアクセスする必要があります。ここで、ポインター/参照/オブジェクトはを参照します派生クラス。

これは、あなたの例では、保護されたメンバーsomethingProtected()Baseオブジェクト、Base *ポインター、またはBase &参照を介してアクセスできませんが、Derivedオブジェクト、Derived *ポインター、Derived &参照。 thisのタイプはDerived *であるsomethingProtected()の単なる省略形であるため、プレーンなthis->somethingProtected()アクセスが許可されます。

b.somethingProtected()は上記の要件に違反しています。

上記の規則に従って、

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

両方が同じエンティティにアクセスしようとしても、最初の呼び出しは失敗し、2番目の呼び出しはコンパイルされます。

75
AnT

基本クラスのメンバーにアクセスする方法について、混乱があると思います。それはこの方法だけです:

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クラスのパブリックメソッドにアクセスしているので、2番目の例は問題ありません

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

Derivedクラスは、Derivedオブジェクトの保護された基本メンバーにのみアクセスできます。 (必ずしも)Derivedオブジェクトではないオブジェクトのメンバーにはアクセスできません。失敗する場合は、Base &を介してメンバーにアクセスしようとしていますが、これはDerivedではないオブジェクトを参照している可能性があるため、アクセスできません。

2
Chris Dodd

あなたがしたことは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.
    }
};
1
Deepu