0

Let's say I have an abstract base class, Shape and then three derived classes: Triangle, Rectangle and Pentagon. The derived classes must be created based on a requirement so I could have several of each of the derived classes. The base class has quite a few fields and I was looking for a way to set the base class properties only once and then just set the different fields for the derived classes later. Since you cannot instantiate an abstract class, what is the best way to do this? I was thinking maybe create another class that derives from Shape that only has the properties of Shape, set those properties and then cast it but this seems inefficient and has code smell written all over it. Can someone suggest a better way? Thanks. Below I have written some pseudo code for the situation

public abstract class Shape
{
    public int x, y, z;
}

public class Triangle : Shape
{
   public int a, b, c       
}

public class Facade : Shape
{
}

private Facade InitializeBaseProperties()
{
    Facade f = new Training
    {
       x = 1, y = 2, z = 3
    };
    return f;
}

private void someMethod()
{
   var tmp = InitializeBaseProperties();
   Triangle triangle = tmp;
}
cbutler
  • 833
  • 13
  • 36
  • 1
    I am not sure what you are asking. There are bugs in your code like `Facade f = new Training` as type `Facade` has no relation to `Training` (*I think you meant `Triangle`*) ? They both derive from `Shape` so they are each shapes **but** a `Training` is not a `Facade` and a `Facade` is not a `Training` – Igor Oct 18 '17 at 14:20
  • 4
    `The base class has quite a few fields and I was looking for a way to set the base class properties only once and then just set the different fields for the derived classes later.` <= Use constructor chaining or use a factory pattern. – Igor Oct 18 '17 at 14:22
  • Hi Igor... sorry, Training is the actual object. For the pseudo code it should read Shape. – cbutler Oct 18 '17 at 14:28
  • "I was thinking maybe create another class that derives from Shape that only has the properties of Shape, set those properties and then cast it" - If you had such a base class and created one and set the properties then you wouldn't be able to cast it to one of your derived types. You can't change what an objects type actually is after creating it. So if something is going to end up as a `Triangle` it has to start as a `Triangle`. – Chris Oct 18 '17 at 14:31

2 Answers2

5

It's true that you can't instantiate an abstract class, but that doesn't mean an abstract class can't have a constructor.
Use a constructor in the abstract class and chain it to the concrete implementation classes constructors:

 public abstract class Shape
 {
      protected int _x, _y, _z;
      protected Shape(int x, int y, int z)
      {
          _x = x;
          _y = y;
          _z = z;
      }
 }

Then, in the derived class:

 public class Triangle : Shape
 {
      public Triangle (int x, int y, int z, int a, int b) : base(x,y,z)
      {
          A = a;
          B = b;
      }

      public int A {get;}
      public int B {get;}
 }
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
0

Something like the following is the closest to your current way of doing things. In this setup your InitializeBaseProperties now takes a shape and sets properties on it. You would then pass your triangle to it after it has been created.

private void InitializeBaseProperties(Shape shape)
{
    shape.x = 1;
    shape.y = 2;
    shape.z = 3;
}

private void someMethod()
{
   Triangle triangle = new Triangle();
   InitializeBaseProperties(triangle);
}

This solution requires that the initialization of a Triangle doesn't actually use any of the properties that you are setting in the InitializeBaseProperties method since they won't actually be there yet.

If you need those properties to be there when you construct the object the only way to do this would be to pass them into the constructor of each of your shapes. Other answers have already addressed this so I will not repeat what they have to say.

I should note that I have deliberately provided an answer as close as possible to your original code since I don't know what your actual code looks like. Setting values in the constructor as others have done may well be the better solution but only you can judge what is best in your actual code.

Chris
  • 27,210
  • 6
  • 71
  • 92