Good day everyone.
I have a question about making and using derived classes of some base abstract class.
I can't quite understand how it works.
My goal: Make a basic class that will define what functions there should be, and then create different derived classes. Then to make an array of base class and instantiate in it different derived classes.
For example:
abstract class UIElement
{
//constructor
abstract public UIElement();
//draw element
abstract public void Draw(int mouseX, int mouseY);
//checks if the element is pointed at by mouse
abstract public Boolean IsPointed(int mouseX, int mouseY);
//defines what happens when clicked
abstract public void Click(int mouseX, int mouseY);
//destructor
abstract public ~UIElement();
}
Then create several derived classes and do like that:
UIElement[] qwe = new UIElement[3];
qwe[0] = new UIElementButton();
qwe[1] = new UIElementLabel();
qwe[2] = new UIElementSomethingElse();
1) What is the proper way to do it, because I can't find a definitive answer or an article that would explain it...
2) About class variables, where they should be declared: base class or derived?
3) What if different derived classes have different variables, how that should be addressed?
4) Can derived classes have different constructor including different arguments?
In comments below, questionner is looking for advice on best practices for writing inheritence hierachies with abstract classes
From a general best-practices and correctness point of view, you ought to declare your UIElement base class without abstract on the constructor and without a finalizer. e.g.
public abstract class UIElement
{
//constructor
protected UIElement();
//draw element
public abstract void Draw(int mouseX, int mouseY);
//checks if the element is pointed at by mouse
public abstract bool IsPointed(int mouseX, int mouseY);
//defines what happens when clicked
public abstract void Click(int mouseX, int mouseY);
}
You could then implement derived classes as follows
public class UIElementButton : UIElement
{
// Optional - create parameterless constructor and
// explicitly call base constructor
public UIElementButton() : base()
{
}
// Mandatory - must override abstract methods
public override Draw(int mouseX, int mouseY)
{
}
// Mandatory - must override abstract methods
public override Boolean IsPointed(int mouseX, int mouseY)
{
}
// Mandatory - must override abstract methods
public override void Click(int mouseX, int mouseY)
{
}
}
You are correct that if you define derived classes as per the above, you could instantiate elements and store in an array of the base type as follows:
UIElement[] qwe = new UIElement[3];
qwe[0] = new UIElementButton();
qwe[1] = new UIElementLabel();
qwe[2] = new UIElementSomethingElse();
qwe[0].Click(1, 2); // Invokes UIElementButton.Click
qwe[1].Draw(3, 4); // Invokes UIElementLabel.Draw
You should also be aware there is a UIElement class defined in WPF. This won't be a problem if you define a namespace for your type, but perhaps consider a more explicit type name such as BaseElement to distinguish your custom type.
Regarding your queries in comments:
For further advice on usage of abstract classes, please see All about abstract classes - Codeproject. - Where should class variables be declared: base class or derived? - What if different derived classes have different variables, how that should be addressed? - Can derived classes have different constructor including different arguments?
These are really the topic for different questions or own research on google, however as a starter I can say:
Class variables should be declared in the scope where they are needed. Meaning if you have a variable Guid _uiElementId and want it to be accessed by derived types, it should be declared in the base class and marked as protected. If you have a variable in UIElementButton called Point _mousePoint and only UIElement button needs it, leave it in there and mark as private
That's fine - any type can see its own private variables and protected variables from base classes. Just make sure names don't clash
Yes they can, for instance.
public class UIElementButton : UIElement
{
private string _buttonText;
// Overloaded ctor
public UIElementButton(string buttonText) : base()
{
buttonText = buttonText;
}
// Default constructor. Mark as private or protected
// to hide from external API
public UIElementButton() : base()
{
}
}
Best regards,
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