2015-04-03 17 views
11

Sagen wir, ich habe diesen Code:Warum kann ich nicht auf ein geschütztes Mitglied von einer Instanz einer Basisklasse zugreifen?

class foo{ 
    protected: 
    int a; 
}; 

class bar : public foo { 
    public: 
    void copy_a_from_foo(foo& o){ 
    a = o.a; // Error 
    } 
    void copy_a_from_bar(bar& o){ 
    a = o.a; // OK 
    } 
}; 

int main(){ 
    bar x; 
    foo y; 
    bar z; 
    x.copy_a_from_foo(y); 
    x.copy_a_from_bar(z); 
} 

hier class bar hat keine Probleme das geschützte Mitglied a von einer anderen Instanz derselben Klasse zugreifen, aber wenn ich versuche, das gleiche mit einer Instanz der Basisklasse zu tun foo , der Compiler gibt mir einen Fehler, der besagt, dass a geschützt ist. Was sagt der Standard dazu?

Fehler sind

prog.cpp: In member function 'void bar::copy_a_from_foo(foo&)': 
prog.cpp:3:7: error: 'int foo::a' is protected 
    int a; 
    ^
prog.cpp:9:11: error: within this context 
    a = o.a; 

P. S .: Ich auf this question einen Blick hatte, aber es ist nicht ganz das gleiche: Ich versuche, das geschützte Mitglied von innerhalb der abgeleiteten Klasse.

+1

Gleiche wie http://stackoverflow.com/questions/3060572/c-protected-pointer-member-to -die-gleiche-Klasse-und-Zugriff-Privilegien? rq = 1 –

+0

Die Bearbeitung wurde entfernt, da es sich bei der Frage nicht um den Compiler-Fehler handelt * per se *, geht es mehr um den Grundgedanken hinter der Regel "kann nicht auf geschütztes Mitglied zugreifen Basisklasse " –

+0

@EugeneK-Nr. Ich weiß, dass ich von der Basisklasse aus nicht auf ein geschütztes Mitglied zugreifen kann. Meine Frage ist warum ich nicht kann. –

Antwort

6

Sie können auf die protected Mitglieder einer Basisklasse nur über einen Zeiger oder Verweis auf ein Objekt des abgeleiteten Typs zugreifen.

Wenn Sie

void copy_a_from_bar(bar& o){ 
    a = o.a; 
} 

zu

void copy_a_from_bar(bar& o){ 
    foo& foo_ref = o; 
    a = o.a;  // OK. Accessing it through `bar&` 
    a = foo_ref.a; // Not OK. Accessing it through `foo&` 
} 

ändern Sie den gleichen Fehler sehen.

This SO answer gibt einen Hinweis darauf, warum die protected Mitglieder der Basisklasse eine mögliche Verletzung des protected Status der Basisklasse-Mitglieder sein, den Zugang zu ermöglichen.

Angenommen, Sie haben:

class baz : public foo 
{ 
    void update_a(foo& f) 
    { 
     f.a = 20; 
    } 
}; 

und Verwendung:

bar x; 
baz z; 
z.update_a(x); 

Wenn dies erlaubt wurden, baz die Werte der Mitglieder des bar ändern können. Das ist nicht gut.

+0

Wissen Sie etwas über die Vernunft hinter diesem Verhalten? – MikeMB

+1

Ich weiß es nicht ... Sie schreiben die Frage im Grunde als Antwort auf ... Ich interessiere mich mehr für die Gründe dafür, warum das so ist. –

+1

Um sicherzustellen, dass * nur * abgeleitete Klassen Zugriff auf die geschützten Daten einer Basisklasse haben. – haavee

3

protected bedeutet, dass als Mitglied in abgeleiteten Klassen zugegriffen werden kann. Es tut nicht gewähren abgeleiteten Klassen uneingeschränkten Zugriff.

Die Argumentation (ich würde annehmen) ist so, dass die abgeleitete Klasse den Basistyp ändern kann, um die eigenen Verträge des abgeleiteten Typs zu erhalten. Es muss jedoch nicht auf die geschützten Member anderer abgeleiteter Klassen zugegriffen werden, da dies ihre Verträge ungültig machen könnte.

Ein Vertrag ist ein Versprechen über die Zustände der Mitglieder. Einige Beispielverträge, mit denen Sie vielleicht vertraut sind, befinden sich in den Interna von string: size enthält die Länge der Zeichenfolge im Puffer, und buffer[size] enthält eine Null (Es gibt eine Unmenge an technischen Details hier, aber sie sind unwichtig). Außerdem zeigt der Puffer immer auf null oder eine gültige Null-terminierte Zeichenfolge mit eindeutiger Eigentümerschaft. Die String-Klasse arbeitet hart, um sicherzustellen, dass alle diese Dinge zutreffen.(string hat eigentlich keinen dieser Verträge, da es sich um private Mitglieder handelt, dies ist nur ein Beispiel)

2

Dies ist ein weit verbreiteter Missverständnis, was protected bedeutet. Es bedeutet nicht, dass Sie auf das Element eines Objekts des Basistyps von einem abgeleiteten Typ zugreifen können, sondern nur auf die Unterobjekte, die Teil eines Objekts des abgeleiteten Typs sind.

Die Begründung ist, dass Sie die Kontrolle über das Mitglied für Ihr Objekt erhalten, wo Sie wissen, was Sie tun, aber ohne leicht den Zustand anderer Objekte zu vermasseln. Betrachten Sie dieses Beispiel, wo CachedDoubleValue eine im Cache gespeicherte Wert mit dem doppelten des Wertes in der Basis-Objekt verwaltet:

class Base { 
protected: 
    int x; 
}; 
class CachedDoubleValue : public Base { 
    int y; 
public: 
    void set(int value) { 
     x = value; 
     y = 2 * x; 
    } 
}; 
class AnotherDerived : public Base { 
public: 
    static void setX(Base &b, int value) { 
     b.x = 10; 
    } 
}; 
int main() { 
    CachedDoubleValue a; 
    a.set(1);    // a.x = 1, a.y = 2 
    AnotherDerived::modifyX(a, 10); 
     // Invariant broken: a.x = 10, a.y = 2; a.x != 2 * a.y 
} 
Verwandte Themen