DanilGholtsman
DanilGholtsman

Reputation: 2374

abstract class constructor inheritence with inner classes objects

Let s say I got an abstract class A. There I got some inner classes like here:

public abstract class A
{
        public InnerOne x;
        public InnerTwo y;
        public A(){
           this.x = new InnerOne();
           this.y = new InnerTwo();
        }
        public class InnerOne
        {
            public virtual double value(){
                return 0;
            }
        }
        public class InnerTwo
        {
            public virtual double value(){
                return 0;
            }
        }
}

Then I got it's childrens like this one:

 public class B: A
    {
            public B():base(){

            }
            public class InnerOne: A.InnerOne
            {
                 public override virtual double value(){
                    return 100;
                }
            }
            public class InnerTwo: A.InnerTwo
            {
                 public override virtual double value(){
                    return 100;
                }
            }
    }

So I was think that when I call B constructor like that I will initialize x and y by creating it's inner classes instances. But actually it not works like that. When I call vaule functions like here it returns zeros.

A newobject = new B();
var bv1 = B.x.value();
var bv2 = B.y.value();

Is there way to force B class to initialize it's x and y fields by it's inner class objects (not with objects from parent abstract class) without re-writing it's constructor?

Upvotes: 2

Views: 98

Answers (4)

Henk Holterman
Henk Holterman

Reputation: 273244

The 'inner class' aspect (embedded class definition) only distracts here, it plays no role.

And to answer the question: No, you cannot have 'virtual constructors' that work this way.

There are of course plenty of ways to get 100 instead of 0 as returnvalue but the question is too artificial to suggest one.

Upvotes: 1

embee
embee

Reputation: 1007

B.x and B.y are instances of A.InnerOne and A.InnerTwo, so you're seeing the value returned as 0 as these have nothing to do with B.InnerOne or B.InnerTwo.

The following B constructor would assign x and y to instances of B.InnerOne and B.InnerTwo which would return 100.

public B(){
    this.x = new InnerOne();
    this.y = new InnerTwo();
}

If you wanted A to work in the way you expect, you'd need to pass the inner types you wanted through from the B constructor and create instances of them in the A constructor, something like:

   public B():base(typeof(InnerOne),typeof(InnerTwo)) { ... }

Using Activator.CreateInstance will let you create these types within A's constructor.

Enigmativity's generic solution is better if you always want A used this way, alternatively this way allows you to have multiple constructors for A so you could optionally pass in different types.

Upvotes: 1

Enigmativity
Enigmativity

Reputation: 117064

You can do it, but you must change the definition for class A - and it gets super hairy.

Here's A:

public abstract class A<I1, I2>
    where I1 : A<I1, I2>.InnerOne, new()
    where I2 : A<I1, I2>.InnerTwo, new()
{
    public InnerOne x;
    public InnerTwo y;
    public A()
    {
        this.x = new I1();
        this.y = new I2();
    }
    public class InnerOne
    {
        public virtual double value()
        {
            return 0;
        }
    }
    public class InnerTwo
    {
        public virtual double value()
        {
            return 0;
        }
    }
}

And here's B:

public class B: A<B.InnerOne, B.InnerTwo>
{
    public B():base(){ }
    public class InnerOne: A<InnerOne, InnerTwo>.InnerOne
    {
        public override double value()
        {
            return 100;
        }
    }
    public class InnerTwo: A<InnerOne, InnerTwo>.InnerTwo
    {
        public override double value()
        {
            return 100;
        }
    }
}

Upvotes: 1

Carbine
Carbine

Reputation: 7903

Even though you have defined the classes inside A or B, they are still public and they are accessible outside A or B. Its no different from a class definied outside A or B.

Imagine the same code with the InnerOne and InnerTwo defined outside the class A and B. It will have the same above behavior. Your root of confusion is misunderstanding inner class usage.

Inorder to get 100, inside B you need to explicitly replace the instance of X and Y variables with an instance that overrides those values. Unless you do them you will not get 100.

 public class B: A
    {
            public B():base(){
            X = new OverridenInnerOne();
            Y = new OverridenInnerTwo();
            }
            public class OverridenInnerOne: A.InnerOne
            {
                 public override virtual double value(){
                    return 100;
                }
            }
            public class OverridenInnerTwo: A.InnerTwo
            {
                 public override virtual double value(){
                    return 100;
                }
            }
    }

Upvotes: 2

Related Questions