2010-04-01 11 views
13

Występuje błąd kompilacji, o którym jestem nieco zdezorientowany. To jest na VS2003.Dlaczego chroniony element nadklasy nie może być dostępny w funkcji podklasy, gdy jest przekazywany jako argument?

error C2248: 'A :: y': Nie można uzyskać dostępu do chronionych członka zadeklarowana w klasie 'A'

class A 
{ 
public: 
    A() : x(0), y(0) {} 
protected: 
    int x; 
    int y; 
}; 

class B : public A 
{ 
public: 
    B() : A(), z(0) {} 
    B(const A& item) : A(), z(1) { x = item.y;} 
private: 
    int z; 
}; 

Problem jest z x = item.y;

Dostęp jest określony jako chroniony. Dlaczego konstruktor klasy B nie ma dostępu do A :: y?

Odpowiedz

5

To z tego powodu:

class base_class 
{ 
protected: 
    virtual void foo() { std::cout << "base::foo()" << std::endl; } 
}; 

class A : public base_class 
{ 
protected: 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
}; 

class B : public base_class 
{ 
protected: 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 

public: 
    void bar(base_class *b) { b->foo(); } 
}; 

Gdyby tak było legalne, można to zrobić:

A a; 
B b; 
b.bar(&a); 

A chcesz być wywołanie protected członkiem od B, który ISN” t dozwolone.

+0

Być może zapomniałeś 'wirtualny'? –

+1

Pavel: oops, tak, dodałem słowo kluczowe 'virtual' ... tak naprawdę nie zmienia to mojego punktu, chociaż :) –

1

dokumentacji IBM podsumowuje to najlepiej:

chroniony nonstatic klasę bazową członkiem można uzyskać dostęp przez członków i przyjaciółmi wszelkich klas pochodnych od że klasy bazowej za pomocą jednej z następujący:

  • Wskaźnik do bezpośrednio lub pośrednio pochodnej klasy
  • Odwołanie do klasy pochodnej bezpośrednio lub pośrednio
  • Przedmiotem klasy bezpośrednio lub pośrednio pochodzącym

Zatem używając przykładu powyżej jako podstawa:

B::B(const A& item) : A(), z(1) { 
    // NOT OK because `item` is not a reference to the derived class B 
    //int i = item.y; 

    // OK because `item` reinterpreted as a reference to the derived class B 
    // Do not do this (bad!) -- for illustrative purposes only 
    int i = reinterpret_cast< const B& >(item).y; 

    // OK because it is equivalent to `this->x = i`, 
    // where `this` is a pointer to the derived class B 
    x = i; 
} 
3

innych odpowiedzi wyjaśnić uzasadnienie zapobiegania swój obiekt B dostępu chronione części A w twoim przykładzie, mimo że B 'to-a' A. Oczywiście najłatwiejszym sposobem rozwiązania tego problemu jest udostępnienie części publicznych lub publicznie dostępnych metod dostępu.

Użytkownik może jednak uznać, że jest nieodpowiedni (lub może nie mieć kontroli nad definicją A). Oto kilka sugestii, które pozwolą ci rozwiązać ten problem, zwiększając kolejność podważania kontroli dostępu A. Zauważ, że wszystkie te obejścia zakładają, że class A jest konstrukcją do kopiowania.

W pierwszym przypadku, po prostu użyć konstruktora kopia dla A założyć stan początkowy dla tej części obiektu B, a następnie naprawić go potem:

class B1 : public A 
{ 
public: 
    B1() : A(), z(0) {} 
    B1(const A& item) : A(item), z(1) { 
    // fix up the A sub-object that was copy constructed 
    // not quite the way we wanted 
    x = y; 
    y = 0; 
    } 
private: 
    int z; 
}; 

Uważam, że niezwykle kłopotliwe i prawdopodobnie bardzo podatny na błędy (zakładając, że chcemy, aby obiekt podrzędny A w obiekcie B był inny niż obiekt A przekazywany do konstruktora - nietypowa sytuacja, ale to, co podano w problemie).Jednak fakt, że można to zrobić, daje pewne uzasadnienie dla bardziej wywrotowych przykładów, które następują ...

Następny przykład tworzy tymczasowy obiekt B, który ma dokładny duplikat obiektu A, do którego chcemy uzyskać dostęp. Następnie można użyć tymczasowego B obiektu dostać się do elementów, które były chronione:

class B2 : public A 
{ 
public: 
    B2() : A(), z(0) {} 
    B2(const A& item) : A(), z(1) { 
    // create a special-use B2 object that can get to the 
    // parts of the A object we want access to 
    B2 tmp(item, internal_use_only); 

    x = tmp.y; // OK since tmp is of type B 
    } 

private: 
    int z; 

    // create a type that only B2 can use as a 
    // 'marker' to call a special constructor 
    // whose only purpose in life is to create 
    // a B object with an exact copy of another 
    // A sub-object in it 
    enum internal_use { 
    internal_use_only 
    }; 
    B2(const A& item, internal_use marker) : A(item), z(0) {}; 
}; 

uważam, że rozwiązanie się być nieco mniej kłopotliwe niż pierwszy, ale to wciąż niejasna (moim zdaniem). Posiadanie bastardowej wersji obiektu B tylko po to, aby dostać się do części obiektu, który chcemy, jest dziwne.

Możemy coś z tym zrobić, tworząc specjalny serwer proxy dla obiektów A, który zapewnia wymagany dostęp. Zauważ, że jest to "najbardziej wywrotowe obejście", ponieważ jest to coś, co każda klasa może zrobić, aby dostać się do chronionych części A, nawet jeśli same nie są podklasami A. W przypadku klasy B istnieje pewna legitymacja, aby uzyskać dostęp do chronionych części obiektów A, ponieważ B to-A, a jak już widzieliśmy, istnieją obejścia, które pozwalają nam uzyskać dostęp, które już wykorzystują prawa, które już są class B ma, więc uważam to za czystszą wersję tych obejść w przypadku class B.

+0

Dzięki za tę odpowiedź. Rzeczywiście twoje założenie było poprawne. Chciałem, aby pod-obiekt A w obiekcie B był inny niż obiekt A przekazywany do konstruktora. –

+0

W prawdziwym scenariuszu wszystkie informacje potrzebne do skopiowania były już dostępne za pośrednictwem publicznego interfejsu A, więc użyłem tego po prostu zamiast dostępu do chronionych członków. Właściwie, chroniony członek A był pierwotnie prywatny i zrobiłem go chronionym, aby móc uzyskać do niego dostęp z B. –

+0

@ Michael Burr - Czy istnieje sposób na zmianę chronionego członka A bezpośrednio (nie kopię A, jak pokazano)? – Liton

Powiązane problemy