2016-08-02 11 views
5

Dies ist die code:Warum kann eine abgeleitete Klasse nicht über einen Zeiger auf Base auf ein geschütztes Member ihrer Basisklasse zugreifen?

class TestA 
{ 
protected: 
    int test=12; 

public: 
    TestA() { 
     cout << "test a: " << test << endl; 
    } 
    ~TestA() { 
    } 
}; 

class TestB : public TestA 
{ 
public: 
    TestB(TestA *testA) { 
     cout << "test b: " << testA->test; 
    } 
    ~TestB() { 
    } 
}; 

int main() 
{ 
    TestA *pTestA=new TestA(); 
    TestB *pTestB=new TestB(pTestA); 
} 

Ich bin für den Zugriff von einem protected Mitglied versucht, einen Zeiger mit deutet auf ein TestA Typ Objekt (also eine Instanz von TestA). TestB ist auch abgeleitet von TestA

Warum kann ich nicht darauf zugreifen? Ist es nur "innerhalb" der Klasse zugänglich, wo ich es brauche? Nicht außerhalb mit Zeiger/direkte Deklarationen?

+0

Ich bin Wiedereröffnung diese Frage als die hier erwähnten Antwort ist besser als das ältere Duplikat: (http [ein geschütztes Mitglied einer Basisklasse in einer anderen Unterklasse zugreifen]: // stackoverflow.com/q/11631777/514235). Den anderen schließen. – iammilind

+0

Kurze Antwort: Weil der Standard sagt, das ist verboten. Dementsprechend werden standardkonforme Compiler einen Fehler ausgeben. YMMV, aber ich würde das eigentlich einen Fehler im Standard nennen. – cmaster

+1

@cmaster (Siehe den Beispielcode in meiner Antwort) Wenn es erlaubt ist, ist es möglich, auf die geschützten Mitglieder über einen Zeiger vom Typ "B *" zuzugreifen, der auf eine Instanz von "D1" in der Mitgliedsfunktion von "D2" zeigt. Aber "D1" und "D2" sind in der Tat irrelevant. Es scheint nicht intuitiv zu sein. – songyuanyao

Antwort

7

Wenn public von der Basisklasse erben, werden die geschützten Member der abgeleiteten Klasse ' protect members, auf die in Memberfunktionen der abgeleiteten Klasse zugegriffen werden kann. Aber sie konnten nur durch die abgeleitete Klasse selbst (und seine abgeleiteten Klassen) zugegriffen werden, kann nicht über die Basisklasse zugegriffen werden. Sie können also nicht über den Zeiger TestA auf das Element test zugreifen, aber es ist in Ordnung, über den Zeiger TestB darauf zuzugreifen.

Der Standard enthält einige anschauliche Beispiele dafür. $11.4/1 Protected member access [class.protected]:

(nur einen Teil des Beispielcode halten)

Eine zusätzliche Zugriffsprüfung als die bereits früher in Abschnitt beschrieben [class.access] angewandt wird, wenn ein nicht-statisches Datenelement oder Nicht static Mitgliedsfunktion ist ein geschütztes Mitglied seiner Benennungsklasse ([class.access.base]) 114 Wie bereits beschrieben, wird der Zugriff auf ein geschütztes Member gewährt, da die Referenz in einem Freund oder Member einer Klasse C auftritt. Wenn der Zugriff einen Zeiger auf Member ([expr.unary.op]) bilden soll, ist der geschachtelte-name-specif ier soll C oder eine von C abgeleitete Klasse bezeichnen. Alle anderen Zugriffe beinhalten einen (möglicherweise impliziten) Objektausdruck ([expr.ref]). In diesem Fall wird die Klasse des Objekts Ausdruck C oder eine Klasse von C abgeleitet werden [Beispiel:

class B { 
protected: 
    int i; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    void mem(B*,D1*); 
}; 

void D2::mem(B* pb, D1* p1) { 
    pb->i = 1;     // ill-formed 
    p1->i = 2;     // ill-formed 
    i = 3;      // OK (access through this) 
    B::i = 4;      // OK (access through this, qualification ignored) 
} 

- Ende Beispiel]

Ich bin nicht sicher über Ihr Design Absicht machen TestB Freund von TestA wäre eine einfache Lösung.

+0

Dies ist eine der für mich schwer zu rechtfertigenden Zugriffsregeln. –

+0

Übrigens: "Wenn die öffentliche Instanz von der Basisklasse erbt, werden ihre geschützten Mitglieder zur abgeleiteten Klasse" Schutzelemente ": Gilt das nicht auch für die geschützte Vererbung? Oder sogar privat? –

+0

@ PeterA.Schneider Es gilt auch für "geschützte Vererbung", denn "private Vererbung" wird "ihre geschützten Mitglieder werden zur abgeleiteten Klasse" private Mitglieder ". – songyuanyao

0

Das Konzept der Zugänglichkeit der Klassenmitglieder von WORLD ist hier anwendbar. WORLD kann nur auf öffentliche Mitglieder der Klasse zugreifen, unabhängig davon, wie sie erstellt/abgeleitet werden.

Betrachten Sie das folgende Beispiel:

class A 
{ 
    public: 
     int public_i; 
    protected: 
     int protected_i; 
    private: 
     int private_i; 

    public: 
     A() 
     { 
      public_i = 10; 
      protected_i = 20; 
      private_i = 30; 
     } 
}; 

class C : protected A 
{ 
    public: 
     void Access(void) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 
class D : private A 
{ 
    public: 
     void Access(void) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 
class B : public A 
{ 
    public: 
     void Access(D *pd) 
     { 
      cout << public_i << endl; 
      cout << protected_i << endl; 
      //cout << private_i << endl; // <- Not Allowed b'coz its private here 

      //pd is WORLD here 
      //cout << pd->public_i << endl; // <- Not Allowed b'coz its private here since private inheritance of A by D 
      //cout << pd->protected_i << endl; // <- Not Allowed b'coz its protected here 
      //cout << pd->private_i << endl; // <- Not Allowed b'coz its private here 
     } 
}; 


int main() 
{ 
    A objA; 
    cout << objA.public_i << endl; 
    //cout << objA.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objA.private_i << endl; // <- Not Allowed b'coz its private here 

    B objB; 
    cout << objB.public_i << endl; 
    //cout << objB.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objB.private_i << endl; // <- Not Allowed b'coz its private here 

    C objC; 
    //cout << objC.public_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objC.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objC.private_i << endl; // <- Not Allowed b'coz its private here 

    D objD; 
    //cout << objD.public_i << endl; // <- Not Allowed b'coz its private here 
    //cout << objD.protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << objD.private_i << endl; // <- Not Allowed b'coz its private here 

    //Outside class its all WORLD and WORLD can access only public members. 
    //Objects and Pointers are WORLD. 

    //Same thing is applicable when class members are accessed via pointers. 
    B *pobjB;  //pobjB is WORLD 
    cout << pobjB->public_i << endl; 
    //cout << pobjB->protected_i << endl; // <- Not Allowed b'coz its protected here 
    //cout << pobjB->private_i << endl; // <- Not Allowed b'coz its private here 

    objB.Access(&objD); 
    objC.Access(); 
    objD.Access(); 

    return 0; 
} 
Verwandte Themen