De alguna manera me sorprendió que el siguiente código se compile y se ejecute (vc2012 y gcc4.7.2)
class Foo {
struct Bar { int i; };
public:
Bar Baz() { return Bar(); }
};
int main() {
Foo f;
// Foo::Bar b = f.Baz(); // error
auto b = f.Baz(); // ok
std::cout << b.i;
}
¿Es correcto que este código se compile bien? ¿Y por qué es correcto? ¿Por qué puedo usar auto
un tipo privado, mientras que no puedo usar su nombre (como se esperaba)?
c++
c++11
auto
private-members
Hansmaad
fuente
fuente
f.Baz().i
también está bien, tal como estástd::cout << typeid(f.Baz()).name()
. El código fuera de la clase puede "ver" el tipo devuelto porBaz()
si puede obtenerlo, simplemente no puede nombrarlo.private
existe una conveniencia para describir las API de una manera que el compilador pueda ayudar a hacer cumplir. No está destinado a evitar el acceso al tipoBar
por parte de los usuariosFoo
, por lo que no obstaculizaFoo
de ninguna manera ofrecer ese acceso al devolver una instancia deBar
.#include <iostream>
. ;-)Respuestas:
Las reglas para
auto
son, en su mayor parte, las mismas que para la deducción de tipo de plantilla. El ejemplo publicado funciona por la misma razón por la que puede pasar objetos de tipos privados a funciones de plantilla:¿Y por qué podemos pasar objetos de tipos privados a funciones de plantilla? Porque solo el nombre del tipo es inaccesible. El tipo en sí sigue siendo utilizable, por lo que puede devolverlo al código del cliente.
fuente
public: typedef Bar return_type_from_Baz;
a la claseFoo
en la pregunta. Ahora el tipo se puede identificar por un nombre público, a pesar de estar definido en una sección privada de la clase.private: typedef Bar return_type_from_Baz;
deFoo
, como demostrado .typedef
Los identificadores 'd son ajenos al acceso a los especificadores, públicos y privados.Bar
oSomeDeducedType
? No es que pueda usarlo para llegar a miembros privados declass Foo
nada.El control de acceso se aplica a los nombres . Compare con este ejemplo del estándar:
fuente
Esta pregunta ya ha sido respondida muy bien por Chill y R. Martinho Fernandes.
Simplemente no podía dejar pasar la oportunidad de responder una pregunta con una analogía de Harry Potter:
https://ideone.com/I5q7gw
Gracias a Quentin por recordarme la escapatoria de Harry.
fuente
friend class Harry;
desaparecido allí?friend class Dumbledore;
;)Wizard::LordVoldemort;
al C ++ moderno. En cambio, él llamausing Wizard::LordVoldemort;
. (No se siente tan natural usar Voldemort, honestamente. ;-)Para añadir a las otras respuestas (bueno), he aquí un ejemplo de C ++ 98 que ilustra que el tema realmente no tiene que ver con
auto
nadaEl uso del tipo privado no está prohibido, solo estaba nombrando el tipo. Crear un temporal sin nombre de ese tipo está bien, por ejemplo, en todas las versiones de C ++.
fuente