Maybe the question I've stated isn't the right question, cause I already know the short answer is "you can't".
I have a base class with an overloaded constructor that takes two arguments.
class Building { public BuildingType BuildingType { get; protected set; } public string Address { get; set; } public decimal Price { get; set; } public Building() { BuildingType = BuildingType.General; Address = "Unknown"; } public Building(string address, decimal price) : this() { Address = address; Price = price; } }
The class is using an enum
enum BuildingType { None, General, Office, Apartment }
Now I want to create a child class Office which also has an overloaded constructor. This child class adds another property (Company). In this class, the BuildingType property should off course be set to Office. This is the code.
class Office : Building { public string Company { get; set; } public Office() { BuildingType = BuildingType.Office; } public Office(string address, decimal price, string company) : base(address, price) { Company = company; // BuildingType = BuildingType.Office; // Don't wanna repeat statement } }
I want the second constructor for the Office class to execute both the base(address, price)
constructor as well as the default constructor of the Office class. I want to call the base(address, price)
constructor so I don't have to repeat assigning all the properties of the base class. I want to call the default constructor of the Office class because it sets the BuildingType property to BuildingType.Office.
Now I know I can't using something like this.
public Office(string address, decimal price, string company) : base(address, price) this()
I'm wondering if there's something wrong with my design that makes me want to call both base(address, price) and this(). Maybe I shouldn't be setting the BuildingType in the constructor but somewhere else? I've tried to introduce a field for this.
public BuildingType BuildingType = BuildingType.General;
But then I can't do the same in the child class. I'd be hiding the BuildingType field in the base class so I'd have to use the new
operator in the child class. I've tried making the BuildingType in the base class virtual
, but a field can't be made virtual.
In this simple example the default constructors only assign default values to some properties. But the Building constructor could als be creating a Foundation for the building, while the Office default constructor might create a... (can't think of something, but you get the idea). So then you'd still want to execute both default constructors.
Am I thinking in the wrong direction here?
Based on Jon Skeet's answer and comments, here's my new code. I've changed constructor chaining from least specific to most specific. I've also added the BuildingType
to the constructor of the Building
class, made that constructor protected, and made the property setter private.
enum BuildingType { None, General, Office, Apartment } class Building { private const string DefaultAddress = "Unknown"; public BuildingType BuildingType { get; private set; } public string Address { get; set; } public decimal Price { get; set; } #region Optional public constructors // Only needed if code other than subclass must // be able to create a Building instance. // But in that case, the class itself can be abstract public Building() : this(DefaultAddress, 0m) {} public Building(string address, decimal price) : this(BuildingType.General, address, price) {} #endregion protected Building(BuildingType buildingType) : this(buildingType, DefaultAddress, 0m) {} protected Building(BuildingType buildingType, string address, decimal price) { BuildingType = buildingType; Address = address; Price = price; } } class Office : Building { public string Company { get; set; } public Office() : this("Unknown Office", 0m, null) {} public Office(string address, decimal price, string company) : base(BuildingType.Office, address, price) { Company = company; } }
Can you (Jon Skeet or someone else) please comment on this revised version of the code?
One (minor) problem that isn't solved by this is that the default constructor for the Office class still needs to provide a default address ("Unknown Office"
in the above code). I would still prefer to let the constructor of the base class decide on the address if one isn't specified. So this code still doesn't do exactly what I want.
I could probably solve that by not using constructor chaining in the derived class, but in stead have each of it's constructors directly call the base constructor. That would mean I'd change the default constructor of the Office
class to
public Office() : base(BuildingType.Office)
That would work for this simple example, but if there's some method I'd like to execute on every instantiation of an Office, I'd have to call in in all constructors. That's why constructor chaining sounds like a better idea to me.
Invoke an Overloaded Constructor using “this” keyword We can call an overloaded constructor from another constructor using this keyword but the constructor must be belong to the same class, because this keyword is pointing the members of same class in which this is used.
A default constructor cannot be overloaded in the same class. This is because once a constructor is defined in a class, the compiler will not create the default constructor. Thus, an attempt to overload the default constructor will effectively remove it from the class. The constructor must not use a different name.
Yes, a Class in ABL can have more than Constructor. Multiple instance constructors can be defined for a class that are overloaded with different parameter signatures. If an instance constructor is defined without parameters, that constructor becomes the default instance constructor for the class.
Constructors can be overloaded in a similar way as function overloading. Overloaded constructors have the same name (name of the class) but the different number of arguments. Depending upon the number and type of arguments passed, the corresponding constructor is called.
Your approach isn't the conventional one, which would solve the problem. Instead of making the more specific constructor (the one with lots of parameters) call the parameterless one, do things the other way round - make the parameterless one call the other, providing defaults. This typically leads to all the constructors bar one in each class calling one "primary" one (possibly indirectly, via others) and that "primary" constructor calls make the base constructor call.
class Office : Building { public string Company { get; set; } public Office() : this(null, 0m, null) { } public Office(string address, decimal price, string company) : base(address, price) { Company = company; BuildingType = BuildingType.Office; // Don't wanna repeat statement } }
... and the same in the base class:
class Building { public BuildingType BuildingType { get; protected set; } public string Address { get; set; } public decimal Price { get; set; } public Building() : this("Unknown", 0m) { } public Building(string address, decimal price) { BuildingType = BuildingType.General; Address = address; Price = price; } }
(I would seriously consider making the Building
constructor include a BuildingType
parameter, too.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With