2011-06-21 8 views
5
class private_object 
{ 
private: 
    struct make_public; 
    friend struct make_public; 
    static void method1() {} 
}; 

struct private_object::make_public 
{ 
    class nested_outer 
    { 
    void callFromOuter() 
    { private_object::method1(); } // Should this be an error? 

    class nested_inner 
    { 
     void callFromInner() 
     { private_object::method1(); } // How about this one? 
    }; 
    }; 
}; 

Ten problem z przyjaźnią pojawił się, kiedy próbowałem przesłać projekt open source do kompilacji pod borlandem. Zgodnie z parashift i dwoma częściowo związanymi pytaniami here i here powyższy przykład nie powinien być prawidłowy.Czy znajomi powinni być przechodni w klasach zagnieżdżonych?

Jednak po przetestowaniu go na siedem różnych kompilatorów tylko Borland i DMC skarżył. To zachowanie zaskoczyło mnie, ponieważ nie oczekiwałem, że przyjaźń będzie przechodnia w klasach zagnieżdżonych.

Więc nasuwa kilka pytań:

  • Co to jest prawo zachowania? Zgaduję, że jest to akceptowane przez większość kompilatorów.
  • Jeśli to jest prawidłowe zachowanie, dlaczego ten przypadek przechodzenia przyjaźni jest w porządku?
  • Jeśli jest to poprawne, oznacza to również zmianę standardu. Jakie mogą być przyczyny dopuszczenia tego w standardzie?
  • W przypadku kompilatorów, które odrzuciły ten kod, jakie byłoby odpowiednie obejście tego problemu? Należy pamiętać, że rzeczywisty projekt może zawierać dość głębokie zagnieżdżanie, więc szukam rozwiązania, które będzie częściowo skalowalne.

1. testowany na mingw-gcc 4.5.2, brzękiem, Borland C++ builder2007, Mars cyfrowych, otwartej Watcom, visualc2010 i Comeau internetowym

Odpowiedz

3

w C++ 03, zagnieżdżone klasy nie dostępu private i protected członkowie załączając klasę domyślnie (patrz może §11.8/1). Ale jeśli uczynisz ich przyjacielem zamkniętych klas, wtedy będą mogli uzyskać do nich dostęp. Ale ponownie zagnieżdżona klasa zagnieżdżonych klas nadal nie jest przyjacielem zewnętrznej klasy zamykającej, zagnieżdżona klasa zagnieżdżonej klasy nie może uzyskać dostępu do prywatnych i chronionych członków najbardziej zewnętrznej klasy zamykającej; nie może uzyskać dostępu do prywatnego i chronionego członka natychmiastowej klasy otaczającej, jak wspomniano wcześniej. To, co robisz, jest takie, dlatego nie jest to dozwolone.

C++ Standard (2003) mówi w $ 11,8/1 [class.access.nest]

członkowie zagnieżdżonych klasy nie mają specjalnego dostępu do członków klasy otaczającej, ani klas ani funkcji , które przyznały przyjaźń klasie zamykającej; zwykłe reguły dostępu (klauzula 11) będą przestrzegane.Elementy otaczającej klasy nie mają specjalnego dostępu do członków zagnieżdżonej klasy; zwykle przestrzegane są zasady dostępu (punkt 11).

przykład z samego Standard:

class E 
{ 
    int x; 
    class B { }; 
    class I 
    { 
     B b; // error: E::B is private 
     int y; 
     void f(E* p, int i) 
     { 
      p->x = i; // error: E::x is private 
     } 
    }; 
    int g(I* p) 
    { 
     return p->y; // error: I::y is private 
    } 
}; 

Jest to wada C++ 03 standardu.

Nawiasem mówiąc, jest to wada w standardzie C++ 03. Ponieważ klasa zagnieżdżona jest członkiem, powinien mieć dostęp do użytkowników prywatnych i chronionych, tak jak każdy inny użytkownik:

§9.2/1 (C++ 03):

Członkowie klasy są członkowie danych, funkcje składowe (9,3), zagnieżdżone typy ... zagnieżdżone typy klas (9.1, 9.7) i (7.2) wyliczenia zdefiniowane w klasie ...

Zobacz ten Defect Report:

1

jakoś czuję, że powinno to być dozwolone. Chociaż nie jestem pewien standardowego zachowania. Ktoś może wskazać.

Dla kompilatory, które odrzuciły ten kod, co byłoby właściwe obejście?

Najlepszy mogę myśleć jest, aby opakowanie:

struct private_object::make_public 
{ 
    static void wrap_method1() { private_object::method1(); } 
    // use wrap_method1() everywhere else 
    // ... 
}; 
Powiązane problemy