2015-10-18 18 views
5

Per favore aiutami a capire perché è possibile che una funzione membro della classe restituisca un oggetto classe nidificato privato e perché sia ​​quindi possibile chiamare le funzioni membro su quella classe nidificata privata, ad es. :Accesso alla classe nidificata privata restituita dalla funzione membro

class Y 
{ 
    class X 
    { 
    public: 
     void f() { cout << "Hello World" << endl; } 
    }; 

public: 
    X g() { return X(); } 
}; 

void h() 
{ 
    Y::X x;  // Error, as expected: class Y::X is private. 
    x.f();  // Error. 

    Y y;  // OK. 
    y.g().f(); // OK. But why??? 
} 

ho provato con GCC e Visual C++, e che lo scorso riga di compilazione su entrambi. Non riesco a trovare nulla nello standard C++ che lo renderebbe valido. Qualche idea per cui funziona?

Edit:

Un'altra osservazione:

void i() 
{ 
    Y y; 

    Y::X x2 = y.g(); // Error: class Y::X is private 
    x2.f();   // Error 

    auto x3 = y.g(); // OK 
    x3.f();   // OK 
} 
+4

Entrambe le funzioni sono 'public' e in realtà non si utilizza' X' ovunque. –

+0

La definizione di 'X' è privata, ma la funzione' g() 'è pubblica. Quindi non c'è nessun problema. – Chiel

risposta

5

Fare una classe nidificata private non significa che gli ambiti esterni non possano mai utilizzare un'istanza di tale classe. Gli identificatori di accesso influiscono sui nomi e la funzione main non tenta mai di nomeY::X. L'unico posto in cui è denominato Y::X è compreso tra Y, che ovviamente ha accesso ai propri membri private. Che la funzione restituisca un'istanza di Y::X a main non è particolarmente rilevante.

[C++14: 11/1]: Un membro di una classe può essere

  • private; ovvero, il relativo nome può essere utilizzato solo da membri e amici della classe in cui è dichiarato.
  • protected; cioè, il suo nome può essere usato solo dai membri e dagli amici della classe in cui è dichiarato, dalle classi derivate da quella classe e dai loro amici (vedere 11.4).
  • public; cioè, il suo nome può essere utilizzato ovunque senza restrizioni di accesso.

Certo, la norma non ha alcun testo per esplicitamente unconfuse te e sottolineare che l'accesso ai soggetti stessi non è controllato da queste parole chiave, ma che è sicuramente l'intento e, in ultima analisi, per quanto il legale va.

Lo fa nome Y::X::f, ma che nome è public.

+0

Ora sono curioso: sarebbe stato possibile memorizzare il risultato di 'g()' in una variabile prima dell'introduzione di 'auto'? –

+0

@SvenMarnach: Non vedo come. –

+1

Interessante. Non mi rendevo conto che "auto" permetteva dichiarazioni che sarebbero altrimenti impossibili. Ho sempre pensato che "auto" sia principalmente una caratteristica di comodità. –

1

Qui potete trovare l'esempio che si sta cercando. f1 è pubblico, f2 è privato e innesca l'errore vi aspettate:

#include <iostream> 

class Y 
{ 
    class X 
    { 
     public: 
      void f1() { std::cout << "Hello World" << std::endl; } 
     private: 
      void f2() { std::cout << "Hello World" << std::endl; } 
    }; 

    public: 
     X g() { return X(); } 
}; 

int main() 
{ 
    // Y::X x;  // Error, as expected: class Y::X is private. 
    // x.f();  // Error. 

    Y y;   // OK. 
    y.g().f1(); // OK. Because f1 is public. 
    y.g().f2(); // Error. Because f2 is private. 

    return 0; 
} 
+0

Penso che l'OP si stia chiedendo perché 'yg()' ha funzionato, tanto quanto qualsiasi cosa ... specialmente perché hanno fatto di tutto per mostrare che possiamo ottenere un'istanza a 'Y :: X' finché non evitiamo nominando il suo tipo, usando 'auto'. –

+0

Forse. In tal caso la mia risposta può essere rimossa. Lascia decidere l'OP. – Chiel

+0

Sì, certo. Stavo solo dicendo. –

2

motivo per cui è possibile che una funzione membro della classe per restituire un oggetto classe annidata privato

Una classe annidata è anche un membro della classe e la funzione membro ha il diritto di accesso sul membro privato.

e perché è allora possibile chiamare le funzioni membro del suddetto classe annidata privato

Non stai utilizzando il nome della classe annidata privato qui, vale a dire Y::X. E Y::X::f() è una funzione pubblica, quindi è possibile chiamarla direttamente.

Problemi correlati