Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to initialize field in base class which should be initialized in subclass?

Tags:

c#

oop

My base class Car contains field engine which can not be initialized in base class. I can initialize it in subclass only, for example in ElectricCar i can write engine = new ElectricEngine. However I use field in base class. So I have a field which used but not initialized:

public class Car {

    protected Engine engine;

    public void Start() {
        engine.Start();
        // do something else
    }

    public void Stop {
        engine.Stop();
        // do something else
    }

    public void Diagnose() {
        engine.Diagnose();
        // anotherField.Diagnose();
        // oneAnotherField.Diagnose();
    }

}

How to better initialize engine?

Version 1. Field guaranteed to be initialized but with many fields constructor will look ugly. Bug-free but ugly.

public class Car {

    protected Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void Start() {
        engine.Start();
        // do something else
    }

    public void Stop {
        engine.Stop();
        // do something else
    }

    public void Diagnose() {
        engine.Diagnose();
        // anotherField.Diagnose();
        // oneAnotherField.Diagnose();
    }

}

public class ElectricCar : Car {
    public ElectricCar() : base (new ElectricEngine()) {
    }
}

Version 2. Subclasses should remember to initialize the field, having such "contract" with subclasses may introduce bugs (uninitialized field).

public class Car {

    protected Engine engine;

    public Car() {
    }

    public void Start() {
        engine.Start();
        // do something else
    }

    public void Stop {
        engine.Stop();
        // do something else
    }

    public void Diagnose() {
        engine.Diagnose();
        // anotherField.Diagnose();
        // oneAnotherField.Diagnose();
    }

}

public class ElectricCar : Car  {
    public ElectricCar() {
        engine = new ElectricEngine();
    }
}

Version 3. Field guaranteed to be initialized. Constructor is clear. But calling virtual method from constructor (potentially dangerous, not recommended in general).

public class Car {

    protected Engine engine;

    public Car() {
        InitializeEngine();
    }

    protected abstract void InitializeEngine();

    public void Start() {
        engine.Start();
        // do something else
    }

    public void Stop {
        engine.Stop();
        // do something else
    }

    public void Diagnose() {
        engine.Diagnose();
        // anotherField.Diagnose();
        // oneAnotherField.Diagnose();
    }

}

public class ElectricCar : Car  {
    public ElectricCar() {
    }

    protected void override InitializeEngine() {
        engine = new ElectricEngine();
    }
}

So every version has pros and cons. Which version is better? Or probably you can suggest even something else.

like image 884
Oleg Vazhnev Avatar asked Jan 14 '13 08:01

Oleg Vazhnev


People also ask

How do you explicitly initialize base class?

If you do not explicitly initialize a base class or member that has constructors by calling a constructor, the compiler automatically initializes the base class or member with a default constructor.

How do you initialize a base class constructor?

Use the name of the base class in an initializer-list. The initializer-list appears after the constructor signature before the method body and can be used to initialize base classes and members. class Base { public: Base(char* name) { // ... } }; class Derived : Base { public: Derived() : Base("hello") { // ... } };

Can derived class initialize base member?

The members of base aggregate class cannot be individually initialized in the constructor of the derived class.

How do you initialize a class member?

To initialize a class member variable, put the initialization code in a static initialization block, as the following section shows. To initialize an instance member variable, put the initialization code in a constructor.


1 Answers

Version 3 is sort of a take on the Template method design pattern. If your base class can't provide a reasonable default implementation, but you require every car to have an engine, delegating the creation to the base class is a very appropriate and safe solution. I would slightly adjust your initialization to be something like this:

protected abstract Engine InitializeEngine();

Then in your constructor for Car:

public Car() {
    engine = InitializeEngine();
}

This will make the contract very clear. Your subclasses simply need to provide an engine and your base class will guarantee that the engine variable is assigned after the constructor is called.

like image 108
Marc Baumbach Avatar answered Sep 18 '22 10:09

Marc Baumbach