www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Confused about Inner Classes

reply "Janice Caron" <caron800 googlemail.com> writes:
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:

class Outer
{

    class InnerA
    {
    }

    class InnerB : InnerA
    {
    }
}

Is it the case that InnerB has both a super class (InnerA) and an
outer class (Outer), and, further, that it's super class has an outer
class (also Outer)? So an instance of InnerB can refer to "outer",
"super" and "super.outer" (where "outer" and "super.outer" are the
same thing?)

Let's get even more bizarre:

class OuterA
{
    class Inner A
    {
    }
}

class VeryConfused : OuterA.InnerA
{
}

I'm not sure that even makes sense. It's very hard to wrap my head
around. Is that nonsense?

What are inner classes good for anyway?
Oct 21 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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:

 class Outer
 {

    class InnerA
    {
    }

    class InnerB : InnerA
    {
    }
 }

 Is it the case that InnerB has both a super class (InnerA) and an
 outer class (Outer), and, further, that it's super class has an outer
 class (also Outer)? So an instance of InnerB can refer to "outer",
 "super" and "super.outer" (where "outer" and "super.outer" are the
 same thing?)
Instances of InnerB are instances of InnerA. Just like in normal inheritance, InnerB inherits InnerA's 'outer' member. Since it's all handled by the compiler, I'd imagine it's smart enough not to redeclare a new 'outer' member in InnerB.
 Let's get even more bizarre:

 class OuterA
 {
    class Inner A
    {
    }
 }

 class VeryConfused : OuterA.InnerA
 {
 }

 I'm not sure that even makes sense. It's very hard to wrap my head
 around. Is that nonsense?
AFAIR that won't compile. Inner classes can only be extended by other non-static inner classes in the same outer class. Other uses would be very tricky to implement and probably be useless.
 What are inner classes good for anyway?
Things. ;) I've run into uses for them with about as much frequency as uses for inner functions (which, in my coding style, is to say "fairly often"). They're useful when you need to model an "owner-owned" relationship. Class literals (a form of nested classes) can also come up when doing some clever things.
Oct 21 2007
prev sibling next sibling parent BCS <ao pathlink.com> writes:
Reply to Janice,


 Let's get even more bizarre:
 
 class OuterA
 {
 class Inner A
 {
 }
 }
 class VeryConfused : OuterA.InnerA
 {
 }
as already pointed out that doesn't work. What also doesn't work (but I whish did work) is this class OuterA { class Inner A { } } class OuterB : OuterA { class VeryConfused : OuterA.InnerA { } }
 I'm not sure that even makes sense. It's very hard to wrap my head
 around. Is that nonsense?
 
 What are inner classes good for anyway?
 
say you need to pass around handles that must be used only with the object the created them, or you want to be able to pass object from collection to collection and need to transfer ownership with them. In both cases the inner class can reach back to it's owner and do something.
Oct 21 2007
prev sibling parent 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
instance of the inner class. 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
instance of the inner class. 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