it-swarm.com.de

Warum kann eine abgeleitete Klasse in diesem Code kein durch Aufrufe geschütztes Element darstellen?

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

Ich dachte, dass möglicherweise nur die geschützten Mitglieder von this verwendet werden können und geschützte Mitglieder anderer Instanzen für immer unerreichbar sind.

Aber:

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

Ich fühle mich dadurch irgendwie übel, da ich seit einiger Zeit in C++ programmiere, aber ich konnte keine Erklärung für dieses Verhalten finden.

BEARBEITEN:

Es spielt keine Rolle, ob es sich um dieselbe oder eine andere Instanz handelt:

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

EDIT2:

Wenn es um Zugriffsrechte geht, ist es anscheinend unerheblich, was Instanz einer Klasse verwendet wird:

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

private:
    int a;
};
63
Martin Drozdik

Obwohl die Zugriffssteuerung in C++ auf Klassenbasis (im Gegensatz zur Instanzbasis) funktioniert, weist der Zugriffsspezifizierer protected einige Besonderheiten auf.

Die Sprachspezifikation soll sicherstellen, dass Sie auf ein geschütztes Mitglied eines base subobject zugreifen, das zur abgeleiteten Klasse gehört. Sie sollten nicht in der Lage sein, auf geschützte Mitglieder von unabhängigen Objekten des Basistyps zuzugreifen. Insbesondere können Sie nicht auf geschützte Mitglieder von freistehenden Objekten des Basistyps zugreifen. Sie dürfen nur auf geschützte Mitglieder von Basisobjekten zugreifen, die embedded als Basis-Unterobjekte in abgeleitete Objekte eingebettet sind.

Aus diesem Grund müssen Sie auf geschützte Member über die Syntax pointer->member, reference.member Oder object.member Zugreifen, wobei der Zeiger/die Referenz/das Objekt auf die Erhaltene Klasse.

Dies bedeutet, dass in Ihrem Beispiel auf das geschützte Element somethingProtected() nicht über Base - Objekte, Base * - Zeiger oder Base & - Verweise zugegriffen werden kann, aber über Derived Objekte, Derived * Zeiger und Derived & Referenzen. Ihr einfacher Zugriff auf somethingProtected() ist zulässig, da dies nur eine Abkürzung für this->somethingProtected() ist, wobei this vom Typ Derived * Ist.

b.somethingProtected() verletzt die obigen Anforderungen.

Beachten Sie, dass gemäß den obigen Regeln in

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

der erste Aufruf schlägt ebenfalls fehl, während der zweite kompiliert wird, obwohl beide versuchen, auf dieselbe Entität zuzugreifen.

75
AnT

Ich glaube, Sie haben einige Verwirrung darüber, wie Sie auf Basisklassenmitglieder zugreifen können. Es ist nur so:

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

in Ihrem Beispiel versuchen Sie, auf ein geschütztes Mitglied einer anderen Instanz zuzugreifen.

eine abgeleitete Instanz hat Zugriff auf ihre eigenen geschützten Mitglieder, jedoch nicht auf andere durch Klasseninstanzen geschützte Mitglieder. Dies ist beabsichtigt.

Der Zugriff auf die geschützten Member einer anderen Klasse, von einem anderen Instanz-Member oder von der Hauptfunktion aus erfolgt tatsächlich über den öffentlichen Zugriff ...

http://www.cplusplus.com/doc/tutorial/inheritance/ (In der Tabelle mit den Zugriffsspezifizierern finden Sie die verschiedenen Ebenen.)

Beide Beispiele beweisen dasselbe zum Beispiel:

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

hier erhält Ihre abgeleitete Klasse b als Parameter, sodass sie eine weitere Instanz der Basis erhält. Da b.somethingProtected dann nicht öffentlich ist, entspricht es nicht den Anforderungen.

dies wird erfüllen:

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

ihr zweites Beispiel ist in Ordnung, da Sie auf eine öffentliche Methode in einer anderen d-Klasse zugreifen

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

Die Klasse Derived kann nur in Derived Objekten auf das geschützte Basismitglied zugreifen. Es kann nicht auf das Element in Objekten zugreifen, die (nicht unbedingt) Derived Objekte sind. In den fehlgeschlagenen Fällen versuchen Sie, über ein Base & Auf das Mitglied zuzugreifen, und da dies möglicherweise auf ein Objekt verweist, das nicht Derived ist, kann der Zugriff nicht erfolgen.

2
Chris Dodd

Was Sie getan haben, ist in C++ illegal. Auf ein geschütztes Element kann von einem Objekt einer Klasse nicht zugegriffen werden. Nur Mitgliederfunktionen können auf geschützte Mitglieder zugreifen. protected -Mitglieder verhalten sich genauso wie private Mitglieder, außer wenn sie von einer abgeleiteten Klasse geerbt werden. Betrachten Sie das unten angegebene Programm, um den Unterschied zwischen privaten, öffentlichen und geschützten Mitgliedern zu verstehen.

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