2016-01-04 12 views
5

Zugegeben, dieser Fragetitel klingt ziemlich genau so wie die Frage, die Sie von Mike wiederholt gestellt haben. Ich habe eine ganze Reihe von Fragen auf die gleiche Art und Weise gefunden, aber keine war meine Frage.C++ geschützt: Zugriff auf das geschützte Member der Base aus der abgeleiteten Klasse nicht möglich

Zunächst einmal würde Ich mag ein paar Punkte für den Kontext dieser Frage zu klären:

1, C++ Zugriffskontrolle arbeitet auf einer Klassenbasis eher als Instanz Basis. Daher ist der folgende Code vollständig gültig.

class Base 
{ 
protected: 
    int b_; 

public: 
    bool IsEqual(const Base& another) const 
    { 
     return another.b_ == b_; // access another instance's protected member 
    } 
}; 

2, ich völlig verstehen, warum der folgende Code nicht gültig ist - eine weitere Geschwister Instanz sein kann.

class Derived : public Base 
{ 
public: 
    // to correct the problem, change the Base& to Derived& 
    bool IsEqual_Another(const Base& another) const 
    { 
     return another.b_ == b_; 
    } 
}; 

Jetzt ist die Zeit meine eigentliche Frage zu entladen:

in der abgeleiteten Klasse Angenommen, ich habe eine Reihe von Grundinstanzen. So effektiv, abgeleitet IS A Base (IS-A-Beziehung), und Abgeleitet besteht aus Base (Composite-Beziehung). Ich habe von irgendwo gelesen, dass dies (bezieht sich auf das Design von IS-A und Has-A) ein Designgeruch ist und ich niemals ein solches Szenario haben sollte. Nun, das mathematische Konzept von Fractals zum Beispiel kann sowohl durch IS-A- als auch Has-A-Beziehungen modelliert werden. Lassen Sie uns jedoch die Meinung über Design für einen Moment ignorieren und konzentrieren Sie sich nur auf das technische Problem.

class Derived : public Base 
{ 
protected: 
    Base base_; 

public: 
    bool IsEqual_Another(const Derived& another) const 
    { 
     return another.b_ == b_; 
    } 

    void TestFunc() 
    { 
     int b = base_.b_; // fail here 
    } 
}; 

Die Fehlermeldung angegeben hat bereits den Fehler sehr deutlich, so gibt es keine Notwendigkeit, dass in Ihrer Antwort zu wiederholen:

Main.cpp:140:7: error: ‘int Base::b_’ is protected int b_; ^ Main.cpp:162:22: error: within this context int b = base_.b_;

Wirklich, nach den folgenden zwei Tatsachen, sollte der Code über Arbeit :

1, C++ - Zugriffssteuerung funktioniert auf Klassenbasis statt Instanzenbasis (daher nicht sagen, dass ich nur auf Derived zugreifen kann b_; Ich kann nicht auf geschützte Elemente einer Standalone-Basisinstanz zugreifen - es ist auf Klasse Basis).

2, Fehlermeldung "innerhalb dieses Kontexts" - der Kontext ist abgeleitet (Ich habe versucht, auf das geschützte Mitglied einer Basisinstanz von Derived zuzugreifen. Es ist das eigentliche Merkmal eines geschützten Mitglieds - es sollte darauf zugegriffen werden können von innerhalb der Basis oder etwas, das von Basis ableitet.

warum wird der Compiler mir diesen Fehler geben?

Antwort

1

das hat nichts mit bases_ zu tun in Derived geschützt ist, geht es um b_ in Base geschützt.

Wie bereits erwähnt, kann Derived nur auf geschützte Elemente seiner Basisklasse zugreifen, nicht auf andere Objekte Base. Nicht einmal, wenn sie Mitglieder von Derived sind.

Wenn Sie wirklich Zugriff benötigen, können Sie Derived einen Freund auf Base machen.

+1

Hallo Bo. Danke für die schnelle Antwort. Hier ist der verwirrende Teil: Der Klärungspunkt 1, bevor ich meine Frage löste, ist genau das, wovon ich mich selbst nicht überzeugen kann. Sie sehen, ich habe auf das geschützte Mitglied einer völlig unabhängigen Base-Instanz zugegriffen und der Compiler war damit einverstanden. – h9uest

+0

Ich hätte das als Quizfrage versäumt. Hast du eine Begründung dafür? Schließlich ist Derived eine Base, die es nicht unangemessen erscheinen lässt, mit anderen Bases auf privater Basis sozusagen zumindest geschützt zu interagieren ;-). Weil Basen das * können * können. Warum macht die Ableitung von Base eine Klasse - schließlich eine Basis, unter anderem! - diese Fähigkeit verlieren? –

+0

Um eine Antwort auf meine eigene Frage zu geben: Eric Lippert hat über die äquivalente Regel in C# geschrieben und scheint einfach zu glauben, dass weniger strenge Semantik für 'protected' nicht ausreichend schützen würde (in seinem Kommentar zu seinem Blog https: // blogs .msdn.microsoft.com/ericlippert/2005/11/09/why-cant-i-Zugriff-a-protected-member-from-a-derived-Klasse/# comment-2844). Er führt das nicht aus, aber ich nehme folgendes an: Bei gegebenem Säugetier A könnte der Benutzercode den geschützten Säugetierzustand von A "legal" durch ein dummes Geschwister-Säugetier B ändern, ein "Angriff", gegen den A nicht "schützen" könnte die Designer. –

2

Die Zugriffsregeln grundsätzlich könnten eine Ausnahme für diesen speziellen Fall vorgesehen, wo es ist bekannt, dass Base ist die meisten abgeleiteten Klasse, der dynamische Typ des Objekts. Aber das hätte die Dinge kompliziert gemacht. C++ ist ausreichend kompliziert.Eine einfache Abhilfe besteht darin, eine staticprotected Accessor-Funktion in Base bereitzustellen.

Eine hack'ish Workaround ist es, die berüchtigte Typ-System-Lücke für Member-Zeiger zu verwenden. Aber ich würde für die static Funktion gehen, wenn ich beim grundlegenden Design bleiben müsste. Weil ich denke, dass es nicht viel Sinn hat, ein paar Tastenanschläge zu speichern, wenn der resultierende Code schwer zu bekommen ist und für die Betreuer schwer zu verstehen ist.


Konkretes Beispiel:

class Base 
{ 
protected: 
    int b_; 

    static 
    auto b_of(Base& o) 
     -> int& 
    { return o.b; } 

public: 
    auto IsEqual(const Base& another) const 
     -> bool 
    { 
     return another.b_ == b_; // access another instance's protected member 
    } 
}; 
+1

Ich denke, die Sondervorschrift für "statisch-probable-most-derived-Bases" wäre auch nicht wünschenswert, denn selbst wenn das fragliche Objekt tatsächlich eine "Base" ist, sollte Code * außerhalb * von "Base" nicht murren mit seinen geschützten Mitgliedern.Ein 'Abgeleitetes 'darf nur mit * seinen eigenen * geschützten Basisklassenmitgliedern spielen, weil es Autorität über sie hat. Jeglicher Zugriff durch andere Klassen erfordert Freundschaftsdeklarationen oder andere Bestimmungen * innerhalb des "Base" -Codes *, dh "Base" muss darüber Bescheid wissen und sich dessen bewusst sein. - Ob das im Allgemeinen zu restriktiv ist, ist natürlich strittig . –

+0

Upvoted für die "statische" Problemumgehung (obwohl es in der Praxis hässlich ist, ist es eine relativ elegante Lösung). –

+0

Danke für Ihre Antwort. Ehrlich gesagt, ich denke nicht, dass C++ diese Ausnahme bereitstellen sollte. Ich denke, C++ sollte den Klärungspunkt 1 in meiner ursprünglichen Frage verbieten. d. h. geschützt sollte auf einer Basis von BOTH-Klasse UND-Instanz statt JUST-Klasse arbeiten. Wie @ Peter A. Schneider und sein Blogbeitrag zeigen, glaube ich, dass dieses "Schutzniveau" schon lange das Ziel hatte zu erreichen und hätte erreichen sollen. Aber ich bin nicht hier, um den Standard zu machen, ich bin hier, um es zu verstehen. Der C++ - Standard scheint sich selbst zu widersprechen. Was denken Sie? – h9uest

2

2, Error message says "within this context" - the context is Derived(I was trying to access a Base instance's protected member from within Derived. It's the very feature of a protected member- it should be able to be accessed from within Base or anything that derives from Base.

Okay, hatte für diese eine die Norm zu gehen.

Sie fragen also: "Warum ist das nicht möglich?" Die Antwort: Weil, wie die Standard-wirklich definiert geschützten Zugang Mitglied:

§ 11.4 Protected member access

[1] An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class...As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C.

(Hervorhebung von mir)

Also lassen Sie sich über Ihre Beispiele geht um zu sehen, was was ist.

class Base 
{ 
protected: 
    int b_; 

public: 
    bool IsEqual(const Base& another) const 
    { 
     return another.b_ == b_; // access another instance's protected member 
    } 
}; 

Kein Problem. another.b_ ist Base::b_, und wir greifen von einer Mitgliedsfunktion Base::IsEqual(const Base&) const darauf zu.

class Derived : public Base 
{ 
public: 
    // to correct the problem, change the Base& to Derived& 
    bool IsEqual_Another(const Base& another) const 
    { 
     return another.b_ == b_; 
    } 
}; 

Hier wir Zugriff auf Base::b_ wieder, aber unser Zusammenhang ist Mitglied Funktion Derived::IsEqual_Another(const Base&) const, das nicht Mitglied von Base ist. Also geh nicht.

Jetzt für den mutmaßlichen Täter.

class Derived : public Base 
{ 
protected: 
    Base bases_[5]; 

public: 
    bool IsEqual_Another(const Derived& another) const 
    { 
     return another.b_ == b_; 
    } 

    void TestFunc() 
    { 
     int b = bases_[0].b_; // fail here 
    } 
}; 

bases_[0].b_ zugreift die Base::b_ geschützt innerhalb des Kontextes des Derived::TestFunc(), der kein Mitglied ist (oder Freund ...) von Base.

So sieht aus wie der Compiler in Übereinstimmung mit den Regeln handelt.

+0

Die Erklärung des OP zu den Grundprinzipien für den allgemeinen Fall "Eine andere kann eine Geschwister [Klasse] sein" ist gut. Das obige ist nur, wie der Standard diese Begründung implementiert. Er beantwortet nicht die Frage des OP und nicht einmal die Grundprinzipien (die sich das OP selbst gestellt hat), noch bietet es eine Lösung. –

+0

@ Cheersandthth.-Alf Wie geht das? Wenn Sie das tun, 'void Abgeleitet :: f() {Base b; b.b_; } 'Es gibt keine Möglichkeit, auf Geschwister zuzugreifen, und es ist immer noch ein Fehler. Die Begründung ist natürlich größer als das (obwohl es mich überrascht hat, bevor ich es überprüft habe). –

+0

Ja, darum geht es in der Frage des OP, warum es immer noch ein Fehler ist. Nicht * wie * die Regeln des Standards machen es zu einem Fehler, aber * warum *. –

2

Ich mache nur meine Kommentare zu einer Antwort, weil ich das Problem interessant finde. Insbesondere in der folgenden minimalen Beispiel ist D nicht mich verwirrt kompilieren:

class B   { protected: int i;   }; 
class D : public B { int f(B &b){ return b.i; } }; 

Denn ein D ein B und sollte alles tun können, die ein B tun können (außer Zugang B ‚s Privat Mitglieder), sollte es nicht?

Offenbar fanden die Sprachdesigner von C++ und C# das zu nachsichtig.Eric Lippert commented one of his own blog posts sagen

But that’s not the kind of protection we’ve chosen as interesting or valuable. "Sibling" classes do not get to be friendly with each other because otherwise protection is very little protection.

EDIT:
Da scheint es einige Verwirrung über die tatsächliche Regel nach 11,4 gelegt sein ich es analysieren werde und die Grundidee mit einem kurzen Beispiel veranschaulichen.

  1. Der Zweck des Abschnitts ist dargelegt, und was es betrifft (nicht statische Mitglieder).

    An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2)

    Die Namensgebung Klasse im Beispiel unten B.

  2. Der Kontext wird erstellt, indem das Kapitel soweit zusammengefasst wird (es wurden Zugriffsregeln für geschützte Mitglieder definiert). Zusätzlich wird ein Name für eine "Klasse C" eingeführt: Unser Code soll sich innerhalb einer Mitglieds- oder Freund-Funktion von C befinden, d. H. Hat C's Zugriffsrechte.

    As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C.

    "Klasse C" ist auch Klasse C im Beispiel unten.

  3. Erst jetzt ist die eigentliche Prüfung definiert. Der erste Teil behandelt Zeiger auf Mitglieder, die wir hier ignorieren. Der zweite Teil betrifft Ihren alltäglichen Zugriff auf ein Mitglied eines Objekts, das logisch "einen (möglicherweise impliziten) Objektausdruck" beinhaltet.
    Es ist nur der letzte Satz, das war es, die „zusätzliche Kontrolle“ dieser ganze Abschnitt beschreibt für:

    In this case, the class of the object expression [through which the member is accessed -pas] shall be C or a class derived from C.

    Das „Objekt Ausdruck“ können Dinge sein wie eine Variable, einen Rückgabewert einer Funktion oder einem dereferenzierte Zeiger. Die "Klasse des Objektausdrucks" ist eine Kompilierzeit Eigenschaft, keine Laufzeiteigenschaft; Zugriff über eine und das gleiche Objekt kann abhängig von auf den Typ des Ausdrucks für den Zugriff auf das Mitglied verweigert oder gewährt werden.

Dieses Code-Snippet demonstriert das.

class B { protected: int b; }; 

class C: public B 
{ 
    void f() 
    { 
     // Ok. The expression of *this is C (C has an 
     // inherited member b which is accessible 
     // because it is not declared private in its 
     // naming class B). 
     this->b = 1;  

     B *pb = this; 

     // Not ok -- the compile time 
     // type of the expression *pb is B. 
     // It is not "C or a class derived from C" 
     // as mandated by 11.4 in the 2011 standard. 
     pb->b = 1; 
    } 
}; 

Ich fragte mich zunächst über diese Regel und übernehmen die folgenden Gründe:

Die Frage auf der Hand Dateneigentum und Autorität.

Ohne Code innerhalbB explizit den Zugriff bereitstellt (von C ein Freund oder durch so etwas wie Alf statische Accessor machen) keine anderen Klassen, außer denen, die „eigene“ die Daten erlaubt, darauf zuzugreifen. Dies verhindert den unerlaubten Zugriff auf die geschützten Member einer Klasse, indem einfach ein Geschwister definiert und Objekte der ursprünglichen abgeleiteten Klasse durch das neue und vor dem unbekannten Geschwistermodell geändert werden. Stroustrup spricht in diesem Zusammenhang von "subtilen Fehlern" in der TCPPL.

Während es sicher wäre, auf (verschiedene) Objekte der ursprünglichen Basisklasse von einem abgeleiteten Klassencode zuzugreifen, betrifft die Regel einfach Ausdrücke (eine Kompilierzeiteigenschaft) und keine Objekte (eine Laufzeiteigenschaft)). Während die statische Codeanalyse zeigen kann, dass ein Ausdruck eines Typs Base sich eigentlich nie auf ein Geschwister bezieht, wird dies nicht einmal versucht, ähnlich wie bei den Regeln für Aliasing. (Vielleicht ist das, was Alf in seinem Beitrag gemeint hat.)

Ich denke, das zugrundeliegende Design-Prinzip ist das Folgende: Garantie Eigentum und Autorität über Daten gibt eine Klasse die Garantie, dass sie Invarianten im Zusammenhang mit den Daten ("nach der Änderung protected a immer auch ändern b "). Die Möglichkeit, eine geschützte Eigenschaft durch eine Schwester zu ändern, kann die Invariante zerstören - ein Geschwister kennt die Details der Implementierungen seiner Geschwister nicht (die möglicherweise in einer weit entfernten Galaxie geschrieben wurden). Ein einfaches Beispiel wäre eine Basisklasse Tetragon mit geschützten Datenelementen width und height plus trivialen öffentlichen virtuellen Zugriffsmethoden. Daraus stammen zwei Geschwister, Parallelogram und Square. Square Accessoren werden außer Kraft gesetzt, um immer auch die andere Dimension zu setzen, um die Invariante eines Quadrats von gleich langen Seiten zu erhalten, oder sie benutzen nur eine der beiden. Wenn nun ein einen Square 's width oder height direkt über eine Tertragon Referenz setzen könnte, würden sie diese Invariante brechen.

+0

Peter, der Blogbeitrag, den du geteilt hast, ist total genial. In Bezug auf die Gründe für Dateneigentum und Autoritäten stimme ich Ihnen vollkommen zu. Vor langer Zeit dachte ich, dass protected auf Instanz AND class basieren sollte - d. H. Der Klärungspunkt 1, bevor ich meine Frage löschte, sollte NICHT funktionieren. Ich musste jedoch zugeben, dass mein vorheriges Verständnis falsch war, weil: 1) der Klärpunkt in der Praxis korrekt ist; 2) Gemäß der Definition von protected in C++ - Standard, Klausel 11 auf Seite 237, kann ein geschützter Name von abgeleiteten Klassen verwendet werden. Was denken Sie? – h9uest

+0

@ h9uest Ich denke, für Dinge wie Zuweisung und andere Operationen mit zwei Instanzen eines Typs ist es sinnvoll, geschützte Mitglieder anderer Instanzen zu manipulieren. –

+0

Herzlichen Glückwunsch Peter. Das C++ Standardkomitee denkt anscheinend genauso. Siehe meine eigene Antwort unten. Ich überprüfte den Quellcode von gcc und verglich das mit dem C++ - Standard und kam zu dem Schluss, dass der Standard den geschützten Memberzugriff weiterhin auf Klassenbasis haben soll, mit Ausnahme der Szenarios wie Zuweisung, Gleichheit, Operatorüberlastung usw. Auf das geschützte Member kann direkt über eine Instanz zugegriffen werden. – h9uest

0

Ok, ich habe diese böse Sache für eine Nacht belästigt. Endlose Diskussionen und die Mehrdeutigkeit der Klausel 11.4 (wie von Yam marcovic zitiert)

§ 11.4 Protected member access

[1] An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class...As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C.

haben mich ausgebrannt. Ich entschied mich, auf den gcc-Quellcode (gcc 4.9.2 in meinem Fall) zurückzugreifen, um zu prüfen, wie diese gcc-Leute die Klausel 11.4 verstanden haben und welche Prüfung genau die C++ - Standards machen wollen und wie diese Prüfungen durchgeführt werden sollen.

In gcc/cp/SEARCH.C:

/* Returns nonzero if it is OK to access DECL through an object 
indicated by BINFO in the context of DERIVED. */ 

static int protected_accessible_p (tree decl, tree derived, tree binfo) 
{ 
    access_kind access; 

    /* We're checking this clause from [class.access.base] 

    m as a member of N is protected, and the reference occurs in a 
    member or friend of class N, or in a member or friend of a 
    class P derived from N, where m as a member of P is public, private 
    or protected. 

Here DERIVED is a possible P, DECL is m and BINFO_TYPE (binfo) is N. */ 

    /* If DERIVED isn't derived from N, then it can't be a P. */ 
    if (!DERIVED_FROM_P (BINFO_TYPE (binfo), derived)) 
    return 0; 

    access = access_in_type (derived, decl); 

    /* If m is inaccessible in DERIVED, then it's not a P. */ 
    if (access == ak_none) 
    return 0; 

    /* [class.protected] 

When a friend or a member function of a derived class references 
a protected nonstatic member of a base class, an access check 
applies in addition to those described earlier in clause 
_class.access_) Except when forming a pointer to member 
(_expr.unary.op_), the access must be through a pointer to, 
reference to, or object of the derived class itself (or any class 
derived from that class) (_expr.ref_). If the access is to form 
a pointer to member, the nested-name-specifier shall name the 
derived class (or any class derived from that class). */ 
    if (DECL_NONSTATIC_MEMBER_P (decl)) 
    { 
    /* We can tell through what the reference is occurring by 
chasing BINFO up to the root. */ 
    tree t = binfo; 
    while (BINFO_INHERITANCE_CHAIN (t)) 
    t = BINFO_INHERITANCE_CHAIN (t); 

    if (!DERIVED_FROM_P (derived, BINFO_TYPE (t))) 
    return 0; 
    } 

    return 1; 
} 

Der interessanteste Teil ist dies:

if (DECL_NONSTATIC_MEMBER_P (decl)) 
    { 
    /* We can tell through what the reference is occurring by 
chasing BINFO up to the root. */ 
    tree t = binfo; 
    while (BINFO_INHERITANCE_CHAIN (t)) 
    t = BINFO_INHERITANCE_CHAIN (t); 

    if (!DERIVED_FROM_P (derived, BINFO_TYPE (t))) 
    return 0; 
    } 

1) im Code abgeleitet ist der Kontext, der in meinem Fall ist die Abgeleitete Klasse;

2) binfo im Code repräsentiert die Instanz, deren nicht statisch geschütztes Mitglied Zugriff hat, in meinem Fall ist dies base_, Derived's geschütztes Datenelement Base instance;

3) decl im Code steht für base_.b_.

Was gcc tat, als mein Code in Frage zu übersetzen ist:

1) überprüfen, ob base_.b_ nicht statisch geschütztes Mitglied ist? ja natürlich, also gib das if ein;

2) Aufstieg auf den Vererbungsbaum von base_;

3) herausfinden, was der tatsächliche Typ base_ ist; natürlich, es ist Basis

4) überprüfen, ob das Ergebnis in 3), die Base ist, abgeleitet von Derived. Natürlich ist das negativ. Dann Rückgabe 0 - Zugriff verweigert.

Anscheinend ist die vom C++ - Standard angeforderte "zusätzliche Prüfung" gemäß der Implementierung von gcc die Typprüfung der Instanz, über die auf das geschützte Element zugegriffen wird. Obwohl der C++ - Standard nicht explizit erwähnt, welche Prüfung durchgeführt werden sollte, denke ich, dass die Überprüfung von gcc die vernünftigste und plausibelste ist - es ist wahrscheinlich die Art von Prüfung, die der C++ - Standard verlangt. Und dann läuft die Frage wirklich auf den Grund für den Standard hinaus, eine zusätzliche Überprüfung wie diese zu verlangen. Dadurch wird der Standard effektiv widerlegt. Diesen interessanten Abschnitt loszuwerden (Es scheint mir, dass der C++ - Standard absichtlich nach Inkonsistenz fragt), der Code sollte perfekt funktionieren. Insbesondere wird das Geschwister Problem nicht auf, da sie durch die Anweisung gefiltert werden:

if (!DERIVED_FROM_P(BINFO_TYPE(t), derived)) 
     return 0; 

die Art des Schutzes In Bezug auf (geschützt nicht rein auf Klasse nicht funktioniert, aber auf beide Klassen- und Instanz) erwähnt von Peter und der Beitrag (von Eric Lippert), den er geteilt hat, stimme ich persönlich voll und ganz zu. Wenn man sich den Wortlaut des C++ Standards ansieht, tut er dies leider nicht; Wenn wir akzeptieren, dass die gcc-Implementierung eine genaue Interpretation des Standards ist, was der C++ - Standard wirklich verlangt, ist ein geschütztes Mitglied durch seine Benennungsklasse oder alles, was von der Benennungsklasse abgeleitet ist, zugänglich; Wenn jedoch über ein Objekt auf das geschützte Member zugegriffen wird, stellen Sie sicher, dass der Typ des Eigentümerobjekts mit dem Typ des aufrufenden Kontexts übereinstimmt. Sieht so aus, als ob der Standard für den Klärungspunkt 1 in meiner ursprünglichen Frage eine Ausnahme machen möchte.

Last but not least, möchte ich Yam marcovic für den Hinweis auf Klausel 11.4 danken. Du bist der Mann, obwohl deine Erklärung nicht ganz richtig war - der Kontext muss nicht Basis sein, es kann Base sein oder irgendetwas, das von Base abgeleitet ist. Der Catch befand sich in der Typprüfung der Instanz, über die auf das nicht statische geschützte Member zugegriffen wurde.

+0

Kurioserweise lässt Ihr Angebot oben die eigentlichen zusätzlichen 11,4 Mandate aus. Kann das eine Quelle der Verwirrung sein? Was du zitierst ("Zugang zu einem geschützten Mitglied wird gewährt, weil ...") ist nur eine Wiederholung der Regeln ("wie zuvor beschrieben"). Die tatsächliche zusätzliche Prüfung ist "die Klasse des Objektausdrucks [über den das in Frage stehende Mitglied zugegriffen wird -pas] soll C oder eine von C abgeleitete Klasse sein." C ist die Klasse des Ortes im Quellcode. Keine Vorfahren, keine Geschwister. –

+0

Ich bemerkte, dass @YamMarcovic auch nicht den wichtigen Teil zitiert. Ich denke nicht, dass der Standard hier widersprüchlich ist. –

+0

@ PeterA.Schneider Ja, Sie haben Recht. Danke, dass ich darauf hingewiesen habe, dass ich den eigentlichen Zusatzcheck weggelassen habe. Mein Fehler. Mit der "arroganten" Behauptung, der Standard sei inkonsistent, verwies ich jedoch auf die Tatsache, dass der Standard den externen Zugriff auf das nicht-statische geschützte Mitglied einer Klasse verhindern möchte, während er für den Klärungspunkt 1 in meinem Fall eine Ausnahme machte ursprüngliche Frage. Wirklich, das ist der EINZIGE Fall, in dem Sie möglicherweise auf die nicht statischen Mitglieder eines Objekts aus einem irrelevanten externen Kontext zugreifen können. – h9uest

0

Es gibt ein paar lange Antworten und Zitate aus dem Standard, die korrekt sind. Ich beabsichtige, eine andere Sichtweise auf das zu bieten, was geschützt bedeutet, dass es zum Verständnis beitragen könnte. Wenn ein Typ von einem anderen Typ erbt, erhält er ein Basis Unterobjekt. Das Schlüsselwort protected bedeutet, dass jeder abgeleitete Typ aufgrund der Vererbungsbeziehung auf dieses bestimmte Element innerhalb des Unterobjekts zugreifen kann, das es enthält. Das Schlüsselwort gewährt Zugriff auf bestimmte Objekte (s), nicht auf beliebige Objekt des Typs Basis.

Verwandte Themen