www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Confused about Inner Classes

reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
Jarrett Billingsley Wrote:

 "Janice Caron" <caron800 googlemail.com> wrote in message 
 news:mailman.494.1193001500.16939.digitalmars-d puremagic.com...
 Just trying to get my head around inner classes (a new concept for me).

 OK, so inner classes get a hidden "context pointer" to the enclosing
 instance. So far so good. But how does that interoperate with
 inheritance. For example:


Hi, Just to check something here. I may be having a stupid day here. Are you saying there is a pointer member available from any inner class to the outer? This sounds like a useful feature in certain circumstances but not one I've heard of before. When using inner classes in C++ I have to explicitly provide a pointer to the outer class. It looks like D does D do this for us ( http://www.digitalmars.com/d/class.html ). But it also looks like the outer class always has at least one instance of the inner class. In C++ I often declare helper types nested within other classes but I do not expect to have an instance of them created for me. This suggests that a D best coding practice is to make helper types a member of the same module but never nest them. Otherwise, how do I declare something other than a 1-to-1 relationship with a nested class? Regards, Bruce.
Oct 22 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/22/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:
    Just to check something here. I may be having a stupid day here. Are you
saying there is a pointer member available from any inner class to the outer?

I believe that is the case, yes.
. But it also looks like the outer class always has at least one

Other way round, I think. The inner class has always has exactly one instance of the outer class (accessible via the member "outer", or implicitly). The outer class, by contrast, always has exactly one /declaration/ of the inner class. It's definitely weird. I tried this earlier on, and it compiled. (Hope I'm remembering this right!) abstract class OuterA { class Inner { } } class OuterB : OuterA { Inner getInner() { return new Inner()); } } auto a = (new OuterB).getInner; This /looks/ totally weird. The class OuterB has no inner class, and yet it is still able to do new Inner - which is an inner class of OuterA. But it's allowed because OuterA is the superclass of OuterB, so it looks like classes inherit the inner class declarations of parent classes. Conversely, instances of Inner would have access to OuterB's variables (and therefore, OuterA's variables). And no - I haven't really got my head round it either. I'm just playing around, seeing what compiles and what doesn't and trying to grok it.
 This suggests that a D best coding practice is to make helper types a member
of the same module but never nest them. Otherwise, how do I declare something
other than a 1-to-1 relationship with a nested class?

My suspicion is you haven't understood it. Of course, I say this in the full knowledge that I haven't understood it either, and because it seems very hard to understand.
Oct 22 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
 On 10/22/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:
    Just to check something here. I may be having a stupid day here. Are 
 you saying there is a pointer member available from any inner class to 
 the outer?

I believe that is the case, yes.
. But it also looks like the outer class always has at least one

Other way round, I think. The inner class has always has exactly one instance of the outer class (accessible via the member "outer", or implicitly). The outer class, by contrast, always has exactly one /declaration/ of the inner class. It's definitely weird. I tried this earlier on, and it compiled. (Hope I'm remembering this right!) abstract class OuterA { class Inner { } } class OuterB : OuterA { Inner getInner() { return new Inner()); } } auto a = (new OuterB).getInner; This /looks/ totally weird. The class OuterB has no inner class, and yet it is still able to do new Inner - which is an inner class of OuterA. But it's allowed because OuterA is the superclass of OuterB, so it looks like classes inherit the inner class declarations of parent classes. Conversely, instances of Inner would have access to OuterB's variables (and therefore, OuterA's variables).

Almost :) Since Inner doesn't yet know that OuterB exists when it was coded, it doesn't have access to OuterB's variables any more than a function in A has access to B's variables. It does have access to virtual functions that A defined and B overrode. You can look at an inner class as a class which has a context "outer" pointer which points to the outer class instance. The benefit of having inner classes is you don't have to always reference that pointer or worry about passing it to the inner class on construction. It's very similar to the 'this' pointer, which you don't always have to reference to access members of the class. For example, the following two cases are equivalent: class Case1 { int m; Case1Inner getInner() { return new Case1Inner(this); } } class Case1Inner { Case1 context; this(Case1 context) { this.context = context; } int getM() { return context.m; } } .... class Case2 { int m; Case2Inner getInner() { return new Case2Inner; } class Case2Inner { int getM() { return m; } } }
 And no - I haven't really got my head round it either. I'm just
 playing around, seeing what compiles and what doesn't and trying to
 grok it.

I'm not sure where the concept of inner classes started, but I first encountered them from Java. They are almost a way to do multiple-inheritance, but not quite. They were used in Java a lot with their UI library. For example, let's say you have a class that represents a GUI window with a lot of buttons. You want each button to do something different, and the way the button performes an action is to have an instance of a ButtonHandler interface, which has an activate() method. If you define your class to implement the ButtonHandler interface, then the same method gets called for all the buttons, which is not what you want. So you can define an inner class which implements ButtonHandler and does the right thing for each button. You can even define them anonymously like so: button1.setHandler(new class ButtonHandler { activate() {button1Pressed = true;} }); The anonymous class declared here is an inner class and so has immediate access to all the variables of the outer class, including button1Pressed. hopefully this helps a little :) -Steve
Oct 22 2007