2015-12-13 22 views
16

ho fatto questa semplice classe, che ancora sta giocando con la mia mente:Accesso classe annidata privato

class A { 
private: 
    class B {}; 

public: 
    B getB() { 
     return B(); 
    }; 
}; 

A partire dal C++ 03, questa classe compila bene, ma non c'è proprio nessun sguardo piacevole modo per assegnare il risultato di getB() ad un lvalue, nel senso che:

A::B b = A().getB(); 

non si compila.

ho ottenuto utilizzando un modello intermedio, in questo modo:

template <typename T> 
struct HideType { 
    typedef T type; 
}; 

HideType<A::B>::type b = A().getB(); 

Ma questo sembra proprio terribile, per questo semplice compito di ottenere una variabile lvalue A :: B.

Questo non è più vero a partire da C++ 11, o almeno non è con gcc. Questo codice non è ancora valido:

A::B b = A().getB(); 

Ma questo è valida:

auto b = A().getB(); 

C'è una scappatoia nel rispetto standard per questo?

+1

Rilevante: http://stackoverflow.com/questions/13532784/why-can-i-use-auto-on-a-private-type – OMGtechy

+1

non riesco a [ 'HideType :: tipo b = .. .'] (http://ideone.com/jwsXhG) da compilare, potresti mostrare un MCVE dove accade? Potresti essere interessato alla [struttura di rapina] di litb (http://stackoverflow.com/questions/15110526/allowing-access-to-private-members) per un'alternativa. –

risposta

1

Il fatto che A::B b = A().getB() non funzioni è perché B è un membro di classe privato di A. Se lo rendi pubblico, il tuo codice verrà compilato. Funziona con auto perché auto controlla semplicemente il tipo di oggetto ad esso assegnato senza dover chiamare il costruttore dell'oggetto (proprio come declval). Quindi assegna b con il tipo di ritorno getB presente nella classe A. È possibile modificare il codice nel seguente modo troppo:

decltype(declval<A>().getB()) b = A().getB(); 

(Se declval è nuovo a voi, allora devo dirvi che sarebbe restituire un rvalue del tipo di ritorno della funzione (qui getB il cui ritorno tipo è B) di una classe (qui A) senza chiamare il costruttore della classe! (Questo dovrebbe comunque essere utilizzato con funzioni come decltype e sizeof). Impedisce quindi il sovraccarico di creare un oggetto classe e quindi di utilizzarlo.)

Ora secondo me, non penso che questa sia una scappatoia nello standard, piuttosto sento il loop buco è stato rimosso! È ovvio dal tuo codice, vedi la funzione getB. Quanto è difficile istanziare un oggetto di B perché è definito in privato! In tal caso, lavorare con B diventa difficile. L'idea alla base di questo è che il nome del tipo (ad esempio B) nella classe A non è accessibile ma il tipo è ancora utilizzabile, motivo per cui è possibile ottenere un oggetto di B.Si può capire l'uso di auto se si comprende il codice questo modello: -

#include <iostream> 
#include <type_traits> // for std::is_same 
using namespace std; 
class A 
{ 
    class B 
    {}; 
    public: 
    B getB() 
    { 
     return B(); 
    } 
}; 
template<typename T> 
void check (T b) 
{ 
    cout<<boolalpha; 
    is_same<decltype(declval<A>().getB()), T> x; // checks if T & B are of same type 
    cout<<x.value<<'\n'; 
} 
int main() 
{ 
    A obj; 
    check (obj.getB()); 
    return 0; 
} 

uscita: -

true 

Come il template potrebbe identificare B, quindi auto troppo identifica B.

+0

"* Funziona con' auto' perché è ciò che 'auto' è !!!! Verificherà solo se il tipo assegnato ad esso è valido o meno *" Questo è tutto gergo. – ildjarn

+0

E 'decltype' è C++ 11, proprio come' auto', quindi qual è il punto nel raccomandarlo? –

+0

Questa è solo un'informazione in più per dire all'OP che è possibile accedere all'oggetto di 'B' senza nemmeno usare' auto'. – Anwesha

9

Da standard, la clausola 11 (controllo accessi membro):

Un membro di una classe può essere
- privato; ovvero, il suo nome può essere utilizzato solo da membri e amici della classe in cui è dichiarato.
- protetto; ovvero, il suo nome può essere utilizzato solo dai membri e dagli amici della classe in cui è dichiarato , dalle classi derivate da quella classe e dai loro amici (vedere 11.4).
- pubblico; ovvero, il suo nome può essere utilizzato ovunque senza restrizioni di accesso.

Quindi il controllo di accesso viene applicato ai nomi .

In

auto b = A().getB(); 

non si utilizzano i nomi di privati, quindi è legale, secondo Standard

0

Sembra, c'era un tale difetto in una bozza dello Standard, ma era stato corretto da WP 1170.

Probabilmente, c'è un bug del compilatore. La dichiarazione auto b = A().getB(); comprende la deduzione argomento modello per lo autoidentificatore di tipo, quindi secondo lo standard C++ 11 dovrebbe essere mal formato, poiché tale deduzione di tipo non riesce.

Problemi correlati