4

I found something weird in C++ that I don't understand why it's happening.

I have an inner class with a private struct definition, it looks like this:

#include <string>
class A {
private:
    class B {
    private:
        struct C {
            int lol;
            std::string ok;
        };
    public:
        B() {}
        C* makething();
    };
public:
    A() {}
    void dostuff();
};

C* makething(); simply returns a new struct C, like this:

A::B::C* A::B::makething()
{
    C* x = new C;
    return x;
} 

So now if the implementation for void dostuff(); is like this:

void A::dostuff()
{
    B x = B();
    B::C* thing = x.makething(); // compile error
    thing->lol = 42;
    thing->ok = "some words";
    std::cout << thing->lol << " " << thing->ok;
}

It gives me the error: C2248 'A::B::C': cannot access private struct declared in class 'A::B' This was expected, because struct C is declared as private within class B.

However, if I change the line B::C* thing = x.makething(); to auto thing = x.makething();, it will compile and no longer gives me the error that struct C is private, and then I can modify the struct's values like I did in the makething() function.

Why is this happening? Why does the auto keyword allow me to create instances of privately declared structs or classes?

Edit: I am using Visual Studio Community 2015 as the compiler.

Edit 2: Didn't realize this was a duplicate, couldn't find anything when I was searching for an answer. Thanks for the responses though everyone, it makes sense now.

PhantomWhiskers
  • 218
  • 1
  • 10
  • This sounds like a bug, I'd mention the compiler you're using, along with the version number. – Blindy Dec 01 '15 at 22:58
  • I am using Visual Studio 2015. I added that as an edit to the original post. – PhantomWhiskers Dec 01 '15 at 22:59
  • Yeah, I saw, good. There isn't much I can tell you about this other than it seems wrong, better C++ programmers will pipe in though! – Blindy Dec 01 '15 at 23:00
  • 3
    Not a bug. Access control in C++ applies to *names*, not the thingies ("entities") they refer to. – T.C. Dec 01 '15 at 23:03
  • 2
    Basically, `private` only hides the *name* of the type. You can still deduce it (you could also, for example, pass it as argument to a function template). – Quentin Dec 01 '15 at 23:03
  • @Quentin: Whaaat? Really? But that's ridiculous, if you can deduce the name, why can't you use the name? – einpoklum Dec 01 '15 at 23:12
  • @einpoklum The important part is that a type can have many names, and those names may be in different scopes. Have a look at chill's answer in the dupe. – Baum mit Augen Dec 01 '15 at 23:21
  • 2
    @BaummitAugen: My logic says that if you have a public method returning `B::C*`, I need to be able to instantiate a `B::C*`. Essentially I expect this to be similar to a forward declaration. – einpoklum Dec 01 '15 at 23:23
  • @einpoklum I was a bit unclear : you can deduce the *type*, not its name. – Quentin Dec 02 '15 at 09:04

0 Answers0