Waarom kan een afgeleide klasse geen beschermd lid aanroepen in deze code?

Ik dacht dat misschien alleen de beschermde leden van thisgebruikt kunnen worden en dat beschermde leden van andere instanties voor altijd onbereikbaar zijn.

Maar:

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
    }
};

Ik word hier een beetje misselijk van, aangezien ik al een tijdje in C++ programmeer, maar ik kon geen verklaring voor dit gedrag vinden.

BEWERKEN:

Het maakt niet uit of het dezelfde of een andere instantie is:

int main()
{
    Derived d1, d2;          // Two different instances
    d1.somethingDerived(d2); // This compiles fine
    d1.somethingDerived(d1); // This compiles fine
    return 0;
}

EDIT2:

Het lijkt erop dat als het gaat om toegangsrechten, het helemaal niet uitmaakt welk exemplaarvan een klasse wordt gebruikt:

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

Antwoord 1, autoriteit 100%

Hoewel toegangscontrole in C++ per klasse werkt (in tegenstelling tot per instantie), heeft de toegangsspecificatie protectedenkele bijzonderheden.

De taalspecificatie wil ervoor zorgen dat u toegang krijgt tot een beschermd lid van een basissubobjectdat tot de afgeleide klasse behoort. Het is niet de bedoeling dat u toegang hebt tot beveiligde leden van een aantal niet-gerelateerde onafhankelijke objecten van het basistype. U heeft met name geen toegang tot beveiligde leden van losstaandeobjecten van het basistype. U hebt alleen toegang tot beveiligde leden van basisobjecten die zijn ingebedin afgeleide objecten als basissubobjecten.

Om deze reden moet u toegang krijgen tot beveiligde leden via de syntaxis pointer->member, reference.memberof object.membersyntaxis , waarbij de aanwijzer/referentie/object verwijst naar de afgeleideklasse.

Dit betekent dat in uw voorbeeld het beschermde lid somethingProtected()niet toegankelijk is via Base-objecten, Base *-aanwijzers of Base &referenties, maar het is toegankelijk via Derivedobjecten, Derived *pointers en Derived &referenties. Uw gewone somethingProtected()-toegang is toegestaan, aangezien het slechts een afkorting is voor this->somethingProtected()waarbij thisvan het type Derived *.

b.somethingProtected()schendt de bovenstaande vereisten.

Merk op dat in overeenstemming met de bovenstaande regels in

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

de eerste aanroep zal ook mislukken, terwijl de tweede zal compileren, ook al proberen beide toegang te krijgen tot dezelfde entiteit.


Antwoord 2, autoriteit 4%

Ik denk dat je enige verwarring hebt over hoe je toegang krijgt tot leden van de basisklasse.
Het is alleen op deze manier:

class Derived : public Base
void drivedMethod() {
    Base::baseMethod();
}

in uw voorbeeld probeert u toegang te krijgen tot een beschermd lid van een andere instantie.

een afgeleide instantie heeft toegang tot zijn eigen beschermde leden, maar niet tot beschermde leden van een andere klasse-instantie, dit is zo ontworpen.

In feite zijn toegang tot de beschermde leden van een andere klasse, van andere instantieleden of van de hoofdfunctie in feite beide onder openbare toegang…

http://www.cplusplus.com/doc/tutorial/inheritance/
(kijk naar de toegangsspecificatietabel om de verschillende niveaus te zien)

Beide voorbeelden bewijzen hetzelfde, bijvoorbeeld:

void somethingDerived(Base& b)
    {
        b.somethingProtected();  // This does not

hier krijgt je afgeleide klasse b als parameter, dus het krijgt een andere instantie van base, en omdat b.somethingProtected niet openbaar is, zal het niet voldoen..

dit zal voldoen:

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

je tweede voorbeeld voldoet prima omdat je toegang hebt tot een openbare methode op een andere d-klasse

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

Antwoord 3, autoriteit 2%

De klasse Derivedheeft alleen toegang tot het beschermde basislid in Derivedobjecten. Het heeft geen toegang tot het lid in objecten die (noodzakelijkerwijs) geen Derivedobjecten zijn. In de gevallen die niet lukken, probeert u toegang te krijgen tot het lid via een Base &, en aangezien dit kan verwijzen naar een object dat niet Derivedis, kan de toegang’ niet gemaakt worden.


Antwoord 4

Wat je hebt gedaan is illegaal in C++. Een beschermd lid kan niet worden benaderd door een object van een klasse. Alleen ledenfuncties hebben toegang tot beveiligde leden. protectedleden gedragen zich net als privé leden, behalve wanneer ze worden overgenomen door een afgeleide klasse. Overweeg het onderstaande programma om het verschil tussen privé, openbare en beschermde leden te begrijpen.

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.
    }
};

Other episodes