Nested Classes' Scope

Java scoping rules and inner classes

Static nested classes1 are exactly like external classes except that they have access to all members of the outer class, regardless of access qualifier. They exist apart from any instance of the outer class, so need a reference to an instance in order to access any instance variables or non-static methods of the outer class.

Non-static nested classes (called inner classes) come into existence only in the context of an instance of the outer class. When constructed, they have a second this field automatically generated, which you can access from within the inner class using the syntax Outer.this. Each instance of the inner class is enclosed by a single instance of the outer class. Again, all the access privileges of static nested classes apply to inner classes. But since they already have an instance of the outer class available, they can automatically access instance variables and methods of the outer class.

For a nice (and very detailed) discussion of inner classes and access specifiers, you can read through the Inner Class Specification. It describes, among other things, how a nested class gets access to private members of its outer class(es). A gentler read is the Nested Classes tutorial.

An off-topic aside: Suppose you have this class structure:

public class O {
public O() { ... }

public class I { // an inner class
public I() { ... }
...
}
...
}

and you've created an instance of O:

O outer = new O();

Now suppose you want to create an instance of O.I. you can't just use new O.I() because the new instance of I needs to be enclosed by a specific instance of O. For this, Java provides the following syntax:

O.I inner = outer.new O.I();

Then inner will then have its second this field set to refer to outer.

Note that this "qualified new operator" syntax is only used for inner classes; it would be unnecessary (in fact, an error) if I were a static nested class.

1 You'll often come across the phrase "static inner class" (including, embarrassingly, in an earlier version of this answer). This is incorrect terminology. In Java, "inner classes" are specifically non-static nested classes.

Scope of private variables within inner classes

The fundamental aspect of this is that inner classes (as opposed to static nested classes) are part of their enclosing class. They aren't separate from it, or from each other. So just like other parts of the enclosing class (constructors and methods) have access to all of its private information, so do all the members of the inner classes. Inner classes are, in some sense, a bit of a fiction that we use as a convenient abstraction mechanism. And since inner classes are part of the enclosing class, their private information is its private information, and so is shared with other inner classes.

Inner Class Enclosing Instance and Scope

Let's say we have a class Foo with a static-nested and inner class(Types of Nested Classes):

public class Foo{
// <---------------------------|
void hello() { // |
System.out.print("Hello");// enclosing scope of InnerFoo
} // |
// <---------------------------|
public class InnerFoo{
void world() {
System.out.print("World");
}
}
// <---------------------------------|
public static class StaticNestedFoo{ //|
void world() { // |
System.out.print("World"); // enclosing scope of InnerFoo
} // |
} // |
// <---------------------------------|
}

As can be seen, the enclosing scope of class InnerFoo is the scope(blocks/methods/types) corresponding to where InnerFoo is declared.

Now, if we want to use the InnerFoo class we would need to:

Foo f = new Foo(); // enclosing instance needed to construct InnerFoo
Foo.InnerFoo ifoo = f.new InnerFoo();
ifoo.world();

As marked in the comment, the enclosing instance is the instance(of Foo here) we need to create in order to construct the non-static nested class.

Finally, if we have a static nested class, we don't need the enclosing instance of Foo and can reference it directly:

Foo.StaticNestedFoo sfoo = new Foo.StaticNestedFoo();
sfoo.world();

A static member variable/method of a class is shared by all instances of the class, thus directly accessible by the class name. In a similar way a static nested class, can be thought of being independent of any instance, thus not requiring the enclosing instance to construct.

Source Code

Related: What is enclosing scope in Java?, really confused by "enclosing scope" of javascript es6 arrow function

Accessibility and Visibility in Nested Class C++

What you've created here is a nested class: The name of the nested class exists in the scope of the enclosing class, and name lookup from a member function of a nested class visits the scope of the enclosing class after examining the scope of the nested class.

When you refer to x within Test1::Test2::m() in your example, the compiler is going to go up the scope chain and find the first x to be Test1::x. Because this isn't a static member variable you're getting the error.

If you want to refer to the global x use ::x. I modified your example to demonstrate:

#include <stdio.h>

int x = 0;
class Test1{
public:
char *x;
class Test2{
public:
int m(){
return ::x++;
}
};
};

int main() {
printf("x = %d\n", x);
Test1::Test2 foo;
foo.m();
printf("x = %d\n", x);
return 0;
}

This prints:

x = 0
x = 1

$.02 note on style: If you reserve nested classes for simple data containers that only operate on themselves, as is a common best practice, you won't run into this issue.

Shorten Member Function Scope Specifiers (Nested Classes) (C++)

Qualified type names allow you to define a typedef to represent a qualified class name. You can then use the typedef with the :: (scope resolution) operator to refer to a nested class or class member, as shown in the following example:

class outside
{
public:
class nested
{
public:
static int x;
static int y;
int f();
int g();
};
};
int outside::nested::x = 5;
int outside::nested::f() { return 0; };

typedef outside::nested outnest; // define a typedef
int outnest::y = 10; // use typedef with ::
int outnest::g() { return 0; };

However, using a typedef to represent a nested class name hides information and may make the code harder to understand.

Source : https://www.ibm.com/support/knowledgecenter/en/SSPSQF_9.0.0/com.ibm.xlcpp111.aix.doc/language_ref/cplr061.html



Related Topics



Leave a reply



Submit