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

4 に答える 4

84

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

言語仕様では、派生クラスに属するいくつかの基本サブオブジェクトの保護されたメンバーにアクセスしていることを確認したいと考えています。基本型の無関係な独立したオブジェクトの保護されたメンバーにアクセスできることは想定されていません。特に、基本型の独立したオブジェクトの保護されたメンバーにはアクセスできません。基本サブオブジェクトとして派生オブジェクトに埋め込まれている基本オブジェクトの保護されたメンバーにのみアクセスできます。

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

つまり、あなたの例では、保護されたメンバーsomethingProtected()Baseオブジェクト、Base *ポインター、またはBase &参照を介してアクセスできませんが、Derivedオブジェクト、Derived *ポインター、およびDerived &参照を介してアクセスできます。where is of typeの省略形にすぎないため、プレーンsomethingProtected()アクセスが許可されます。this->somethingProtected()thisDerived *

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

上記の規則に従って、

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

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

于 2013-05-28T06:28:49.073 に答える
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

ここで、派生クラスはパラメーターとして b を取得しているため、ベースの別のインスタンスを取得しています。次に b.somethingProtected が公開されていないため、準拠しません..

これは準拠します:

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

2 番目の例は、別の d クラスのパブリック メソッドにアクセスしているため、問題なく準拠しています。

>  void somethingDerived(Base& b)
>     {
>         b.somethingProtected();  // This does not
>     }
于 2013-05-28T06:19:04.303 に答える
2

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

于 2013-05-28T06:28:19.937 に答える