Search code examples
c++classprivate

C++ private nested class - access to different functions


Found this strange compilation behavior, checked on VS2012, VS2017 and https://www.onlinegdb.com/online_c++_compiler)

Basically for private nested classes you can call public functions outside, but not public constructors.

3 questions:

  • what is the reasoning behind compiler letting me call func()?

  • if compiler lets me call func(), why I cannot call ctor?

  • if I cannot call ctor, how come emplace_back is able to do it?


class Outer {
    struct PrivateInner {
        PrivateInner() {}
        void func() {}
    };
public:
    PrivateInner inner;
    std::vector<PrivateInner> innerVect;
};

void f1()
{
    Outer c;
    c.inner.func(); // COMPILING, but why?
}

void f2()
{
    Outer c;
    c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?
    c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?
}

As I see I still can create a (static) function createObject():

class Outer {
    struct PrivateInner {
        PrivateInner() {}
        static PrivateInner createObject() { return PrivateInner(); }
        void func() {}
    };
.....
};

and then call it.

createObject() may be non-static if calling static from instances is not pure standard thing.

c.innerVect.push_back(c.inner.createObject()); // COMPILING

to "hack" compilation


Solution

  • Note that the nested struct PrivateInner is declared as private, so only Outer::PrivateInner is private, you can't use this name to declare variable like Outer::PrivateInner pi; without sufficient access right, but you can write it like decltype(Outer::inner) pi;.

    On the other hand, its constructor and member function are public, so they can be called.

    c.inner.func(); // COMPILING, but why?
    

    func() is public, so if you have got an instance of type Outer::PrivateInner you can call func on it.

    c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?
    

    It has nothing to do with the constructor, you just can't use the name Outer::PrivateInner here.

    c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?
    

    The constructor is public, then it could be used to construct the object. std::vector doesn't use the name like Outer::PrivateInner directly; it uses the name specified as the template argument.

    BTW: For the same reason,

    c.innerVect.push_back(c.inner.createObject()); // COMPILING
    

    but c.innerVect.push_back(Outer::PrivateInner::createObject()); won't compile.