17

Hello I am wondering why C++ standard allows us in nested classes to access outer class's private fields, while it forbids to access inner class's private fields from the outer class. I understand, that this example:

class OuterClass{
public:
    class InnerClass{
    public:
        void printOuterClass(OuterClass& outer) {cout << outer.m_dataToDisplay;};
    };
private:
    int m_dataToDisplay;
};

is fine, because thing, that Inner class sometimes can be complicated. But I think following scenario is also fine:

class Algorithm{
public:
    class AlgorithmResults{
    public:
        void readAlgorithmResult();
    private:
        void writeAlgorithmResult();
    };

    void calculate(AlgorithmResults& results, Arguments...){
       //calculate stuff
       results.writeAlgorithmResult(results);
    }
};

For me this structure makes perfect sense, although it is not allowed in C++. I also noticed, that for some time both were allowed in Java, but now second example is also forbidden. What is the reason, that first example is allowed and another is denied?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
DawidPi
  • 2,285
  • 2
  • 19
  • 41

3 Answers3

16

Essentially, within a scope names declared earlier in that scope are valid and can be used directly (unless they're shadowed). Code outside a scope can't directly use names declared inside the scope. E.g. code after a curly braces block, can't directly use variables declared inside that block (an example of indirect use is when the outside code has access to a pointer to a static variable inside the curly braces block).


For the second example, just make Algorithm a friend of AlgorithmResults:

class AlgorithmResults
{
    friend class Algorithm;
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 5
    Sorry, I inverted the friendship and had to fix. This is yet another proof that coffee is needed before posting to SO! – Cheers and hth. - Alf Mar 15 '16 at 10:40
  • I'd -1 this answer because it seems confusing availability vs accessibility. I tend to feel things inside a pair of curly braces be UNAVAILABLE out of that scope, not strictly INACCESSIBLE from outside of that scope. – Compl Yue Jul 02 '18 at 08:52
  • @ComplYue: Accessibility is the standard's terminology. Not sure what you mean by UNAVAILABLE as opposed to INACCESSIBLE. Perhaps I should reword to "has direct access", but starting on this road of qualifications one would have to distinguish types from type names for the return types of member functions, and possibly more -- it gets murky and messy fast. – Cheers and hth. - Alf Jul 02 '18 at 11:22
  • I sense UNAVAILABLE as the target has ceased existence, so the subject party has no way to reach it, though the access could be allowed only if the target still exists; while INACCESSIBLE carries more implication of existence than not, but the subject party is prohibited from touching the target by provisional restrictions. I hope I'd made myself a little clearer. – Compl Yue Jul 10 '18 at 07:37
  • I think you have a point regarding imperfect terminology in the answer. I don't agree with your general view. A scope can contain types and static variables and functions and more, that don't cease to exist as execution moves out of the scope; it's not a dynamic thing. But, my choice of terminology was just needlessly **wrong**. Relevant standards quote, C++2017: " In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope". The standard talks about where a name is *valid*, and whether a name is *visible*. It's complex. – Cheers and hth. - Alf Jul 10 '18 at 13:18
  • @ComplYue Updated the answer accordingly, but it may possibly now be needlessly wrong in some other way. Perfection isn't possible for a reasonably short answer about a complex issue. – Cheers and hth. - Alf Jul 10 '18 at 13:22
  • Totally agree that the whole complexity, and I am glad your response has led me to a better understanding of the question and your answer. I feel like that `unless they're declared **public** ` could follow `Code outside a scope can't directly use names declared inside the scope`, is this compatible with your view? And I'd think **protected** need to be mentioned too, though obviously the wording has to go rather messing. But I'd emphasis word **private** in the question, and feel **curly braces** alone can't form a full answer. – Compl Yue Jul 12 '18 at 07:40
8

The nested classes could access outer class's private fields, because it's a member of the outer class, just same as the other members.

[class.access.nest]/1

A nested class is a member and as such has the same access rights as any other member.

On the other hand, the outer class doesn't have special access rights on the nested class, they're just normal relationship.

The members of an enclosing class have no special access to members of a nested class; the usual access rules ([class.access]) shall be obeyed. [ Example:

class E {
  int x;
  class B { };

  class I {
    B b;                        // OK: E​::​I can access E​::​B
    int y;
    void f(E* p, int i) {
      p->x = i;                 // OK: E​::​I can access E​::​x
    }
  };

  int g(I* p) {
    return p->y;                // error: I​::​y is private
  }
};

— end example ]

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
6

Counter question: Why would you want to allow it?

If you need an outer class have access to an inner class' private internals, you can befriend:

    class Foo {
    public:
            class Frob {
                    friend class Foo;
                    int privateDataMember;
            };

            Foo () {
                    Frob frob;
                    frob.privateDataMember = 3735928559;
            }
    };

C++ has no device to unfriend, so allowing default private access to an outer class would steal you a class design tool and yield reduced default encapsulation.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130