teorico - polimorfismo en c++
¿Por qué puedo usar auto en un tipo privado? (4)
El control de acceso se aplica a los nombres . Compare con este ejemplo del estándar:
class A {
class B { };
public:
typedef B BB;
};
void f() {
A::BB x; // OK, typedef name A::BB is public
A::B y; // access error, A::B is private
}
De alguna manera me sorprendió que el siguiente código compila y ejecuta (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 compila bien? ¿Y por qué es correcto? ¿Por qué puedo usar auto
en un tipo privado, mientras que no puedo usar su nombre (como se esperaba)?
Esta pregunta ya ha sido respondida muy bien tanto por chill como por R. Martinho Fernandes.
Simplemente no podía dejar pasar la oportunidad de responder una pregunta con una analogía de Harry Potter:
class Wizard
{
private:
class LordVoldemort
{
void avada_kedavra()
{
// scary stuff
}
};
public:
using HeWhoMustNotBeNamed = LordVoldemort;
};
int main()
{
Wizard::HeWhoMustNotBeNamed tom; // OK
Wizard::LordVoldemort not_allowed; // Not OK
return 0;
}
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:
template <typename T>
void fun(T t) {}
int main() {
Foo f;
fun(f.Baz()); // ok
}
¿Y por qué podemos pasar objetos de tipos privados a funciones de plantillas? Porque solo el nombre del tipo es inaccesible. El tipo en sí todavía se puede usar, por lo que puede devolverlo al código del cliente.
Para agregar a las otras (buenas) respuestas, aquí hay un ejemplo de C ++ 98 que ilustra que el problema realmente no tiene que ver con el auto
en absoluto
class Foo {
struct Bar { int i; };
public:
Bar Baz() { return Bar(); }
void Qaz(Bar) {}
};
int main() {
Foo f;
f.Qaz(f.Baz()); // Ok
// Foo::Bar x = f.Baz();
// f.Qaz(x);
// Error: error: ‘struct Foo::Bar’ is private
}
Usar el 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 ++.