4

Let's consider the next code:

#include <iostream>
#include "mydemangled.hpp"

using namespace std;

struct A
{
private:
    struct B {
       int get() const { return 5; }
    };

public:
   B get() const { return B(); }
};

int main()
{
    A a;
    A::B b = a.get();

    cout << demangled(b) << endl;
    cout << b.get() << endl;
}

And the compiler (gcc 4.7.2) yells saying that A::B is private. All right. So, I change the code:

int main()
{
   A a;

   cout << demangled(a.get()) << endl;
   cout << a.get().get() << endl;
}

and it doesn't yell:

$ ./a.out
A::B
5

Meaning, I can't to create instances of A::B, but I can use it. So, new change (the key of my question).

int main()
{
   A a;
   auto b = a.get();

   cout << demangled(b) << endl;
   cout << b.get() << endl;
}

And output:

$ ./a.out
A::B
5

What is the trouble here, being A::B private (and thus its constructors, copy constructors and so on)?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
ABu
  • 10,423
  • 6
  • 52
  • 103
  • 1
    `private` is not a security feature. – R. Martinho Fernandes Mar 20 '13 at 13:44
  • Security of access/exposition to the exterior I mean – ABu Mar 20 '13 at 13:45
  • That is interesting. I'm still rusty with `auto` - does it perhaps become a `const A::B&`? If it becomes `A::B`, how does it access the private copy constructor? – Drew Dormann Mar 20 '13 at 13:48
  • 3
    @Drew no, it becomes a `A::B`. This is not new in C++11, btw: `template int f(T t) { return t.get(); } f(a.get());` works just fine too, because the rules are the same. You just cannot name the type. – R. Martinho Fernandes Mar 20 '13 at 13:48
  • @R.MartinhoFernandes I learned a thing! Thanks. – Drew Dormann Mar 20 '13 at 13:52
  • Also, note how you can use the type indirectly inside the template function through T http://coliru.stacked-crooked.com/view?id=89165da25c6b5f1311b88578cacc3f91-61c3814520a8d4318f681038dc4b4da7, or outside using decltype http://coliru.stacked-crooked.com/view?id=0dbdb6376ae43b6978a33e46110036ee-61c3814520a8d4318f681038dc4b4da7. The type itself is always usable (otherwise returning it from a public function would not make sense), you just cannot use its name. This is the same logic as allowing you to return references to private members, or pointers to private member functions. – R. Martinho Fernandes Mar 20 '13 at 13:56

1 Answers1

5

In general, access controls names or symbols, not the underlying entities. There are, and always have been, numerous ways of accessing private members; what you cannot do is use the name of such a member.

In your examples, you don't use the name, so there is no problem.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • To see this even better, try doing `typedef B OtherB;` in the public section of `A`. You'll see A::OtherB is accessible from main and `A::OtherB` works perfectly fine. The name itself is the one that's private, the type itself is perfectly accessible. – Ed Rowlett-Barbu Mar 20 '13 at 14:00