3

I have a class that extends a base class. The base class is more generic, and thus needs more parameters. The derived class is a specific type of base class, and thus only needs one of the two parameters the base class needs in its constructor (the derived class can provide the base class with the second parameter, but needs to do some processing first).

Is it possible to have a constructor in the derived class that then invokes the base classes constructor?

I'm aware I could just use : base(int a, int b) if the parameters were passed in directly, but I don't think I can do this since I need to process the second variable before calling the base class constructor.

class Foo {
    private int c;

    public Foo(int a, int b) {
        c = a + b;
    }
}

class Bar : Foo {
    public Bar(int a, bool plusOrMinus) {
        if (plusOrMinus) {
            Foo(a, 5); // calling base class constructor- AFTER processing
        } else {
            Foo(a, -5); // calling base class constructor- AFTER processing
        }
    }
}
jtfairbank
  • 2,311
  • 2
  • 21
  • 33
  • You can't do that. Consider a different approach and design. – Daniel A. White Oct 28 '11 at 16:58
  • You could have another constructor in `Foo` that takes `plusOrMinus`. – Daniel A. White Oct 28 '11 at 16:59
  • 1
    Hmm. Dunno if this works, but I think you can do some tricks like `public Bar(int a, bool isPositive) : base(a, isPositive ? 5 : -5) {}`. – Alxandr Oct 28 '11 at 17:00
  • I have almost same question before http://stackoverflow.com/questions/3423978/why-cant-access-constructor-in-body-of-another-constructor – Freshblood Oct 28 '11 at 17:05
  • 1
    Putting logic in constructors can be a dangerous game. Use with caution. – ElvisLives Oct 28 '11 at 17:09
  • Sorry @Freshblood. I looked through 5 similar questions or so and didn't see yours so I thought it was a new question. My question is a bit different, however- I'm asking how I can achieve the effect, you asked if you could achieve it or not (yes / no). – jtfairbank Oct 28 '11 at 17:09
  • @ElvisLives How so? And in this case I'm simply distinguishing between two options to set the parameter as. – jtfairbank Oct 28 '11 at 17:10
  • @jtfairbank while not *exactly* an answer to logic in contructors, I think the answer to [why you shouldn't use virtual members](http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor) in constructors is very similar and worth mentioning. – Joseph Yaduvanshi Oct 28 '11 at 18:18

6 Answers6

4

One way to do this is to use the ternary operator

public Bar(int a, bool plusOrMinos) : base(a, plusOrMinus ? 5 : -5) {
  ...
}

For more complex conditionals though you should switch to a static factory method

private Bar(int a, int b) : base(a, b) {
  ...
}

public static Bar Create(int a, bool plusOrMinus) {
  if (plusOrMinus) {
    return new Bar(a, 5);
  } else {
    return new Bar(a, -5);
  }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
2

You can just do it inline, no?

public Bar(int a, bool plusOrMinus) : base(a, plusOrMinus ? 5 : -5) {
}

If you need to do something more sophisticated, you can extract the logic out into a static method:

public Bar(int a, bool plusOrMinus) : base(a, GetValueFromPlusOrMinus(plusOrMinus)) {
}

public static int GetValueFromPlusOrMinus(bool plusOrMinus) 
{
    if (plusOrMinus)
        return 5;
    else
        return -5;
}
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
2

You can more or less do this if you can write a static function to process the data:

class Bar : Foo 
{
    public Bar(int a, bool plusOrMinus) : base(a, calc(plusOrMinus))
    {
    }

    private static calc(bool pom) : ...; return -5; }
}
H H
  • 263,252
  • 30
  • 330
  • 514
1

My suggestion is to use composition instead of inheritence.

Instead of having a bunch of subclasses (A, B, C) derive from your base class (X), instead have A, B, C contain a private instance of X that they can call.

This way you only have the shared logic in one place (X) and all your classes are able to use it.

class Foo {
    private int c;

    public Foo(int a, int b) {
        c = a + b;
    }
}

class Bar {
    private Foo _base;

    public Bar(int a, bool plusOrMinus) {
        if (plusOrMinus) {
            _base = new Foo(a, 5);
        } else {
            _base = new Foo(a, -5);
        }
    }
}
Dylan Smith
  • 22,069
  • 2
  • 47
  • 62
1

How about this approach?

class Foo
{
    private int c;

    public Foo(Builder builder)
    {
        c = builder.A ?? 0 + builder.B ?? 0;
    }
}

class Bar : Foo
{
    public Bar()
        : base(new Builder().WithA(2).WithB(3).WithPlusOrMinus(false))
    {

    }
}


public class Builder
{
    public int? A { get; private set; }
    public int? B { get; private set; }
    public bool? PlusOrMinus { get; private set; }

    public Builder WithA(int a)
    {
        A = a;
        return this;
    }

    public Builder WithB(int b)
    {
        B = b;
        return this;
    }

    public Builder WithPlusOrMinus(bool plusOrMinus)
    {
        if(!plusOrMinus)
        {
            B *= -1;
        }
        return this;
    }
}
Jin-Wook Chung
  • 4,196
  • 1
  • 26
  • 45
1

I would prefer making a protected Initialize(...) on the base class and call this at the end of the ctr in the inherited class.

Casper Leon Nielsen
  • 2,528
  • 1
  • 28
  • 37