Qt5 and Pattern for similar dialogs implementation - c++

What is in your opinion the best way to implement similar dialogs in Qt5 without duplicating the code?
This is the problem: having two "slightly different" data structures, with many common parts, implement two "slightly different" QDialog to handle the user interaction.
We have two structures:
class DataA {
public:
int one, two, three;
bool x,y;
SubdataA subA;
}
class DataB {
public:
int one, two, three;
bool x,y;
SubdataB subB;
}
SubdataX is some other structured data we need to handle in the GUI. The two QDialog should handle the common fields the same way, while SubdataX must be handled by specific parts. The code should also make some operation on the data structures, and provide output files. This part is quite easy.
My question is, what are the best strategies to implement this? The objective is to have elegant code that should be quite easy to maintain and as most readable as possible. The framework is Qt, so the solution should be tailored to Qt with qdialog layout in UI files, since the gui layout is too complex to design it by code.
Thank you.

I'm not sure what you mean by "difficult to manage the ancestor class". I think I understand you want a polymorphic input to determine the layout of a dialog box. Is this assumption correct?
For example, given the following classes, you're able to use a dynamic cast to influence the behaviour of a dialog box.
class IData {
public;
int one, two, three;
bool x, y;
};
class DataA : public IData {
public:
// more data in here
};
class DataB : public IData {
public:
// more unique data in here
}
Now, assume you have written a dialog box with a function signature
void configureDialog(IData *data) {
DataA *dataA = dynamic_cast<DataA*>(data);
if (dataA) {
// configure what parts of the QDialog to see here
}
DataB *dataB = dynamic_cast<DataB*>(data);
if (dataB) {
// configure other parts of the QDialog you want to see
}
}
Which would allow for polymorphic configuration of a single QDialog box.

As Tyler Jandreau stated, a possible solution is to use polymorphism.
But this requires a careful planning of architecture and class inheritance, because to avoid using downcasting and a huge and unmaintenable number of switch() cases, you need also to use polymorphism on the GUI classes.
As View/Model architecture requires, the data classes will be mimicked by the control/Gui classes.
Data classes will be implemented using an ancestor, abstract class CommonData that includes the common "fields", and two (or more) concrete data classes derived from CommonData through inheritance. My first idea was to use composition instead, but this would pose other issues when implementing the gui.
So DataA and DataB are derived from CommonData.
On the Gui side, the structure is similar, but due to lack of inheritance support of the UI form classes generated by Qt's uic, we cannot use inheritance. My first guess was to use Template Metaprogramming, and implement the ancestor class as a Template class, but though it worked on the C++ side, moc refuses to parse that class and generate the moc_X file when the Q_OBJECT tagged class is a template.
So we are going to use a mix of inheritance and composition.
This is the architecture: a "container" GUI class (ContainerDialog) implements the GUI for the CommonData class; a PluggableInterface abstract class will define a set of operation (we'll see which below); a set of concrete classes derived from the latter will implement the GUI logic for the remaining classes.
So the ContainerDialog loads a ContainerDialog.ui form as a "standard" QDialog, and manages all the interface with CommonData. His constructor , or a setter will receive a CommonData pointer, remember that CommonData is abstract and cannot be instantiated.
The specific fields are managed thorugh specific graphic components that are "plugged" in the ContainerDialog gui. For example, a method defined in PluggableInterface will insert the QWidget derived component in the ContainerDialog gui. The classes involved are, for example, ComponentA1, ComponentA2, ComponentB, etc...
The use of the abstract interface PluggableInterface and the UI components will prevent the ContainerDialog to know what kind of concrete class are in use, and all the necessary code to instantiate the specific classes can be implemented using some creational pattern (Abstract Factory, Prototypes, etc...)

Related

How can interface return an unknown type?

I'm trying to make a cpp interface class (pure virtual) declare a function that all derived classes must implement. However because the interface class is trying to be ignorant of implementation details, it doesn't know about the type of the returned object, and would like to delegate that to the derived class. The specific type of the returned object is handled by the derived class.
class UIInterface
{
// Should not know about QWidget
// Would like to defer return type until derived class which implements interface
QWidget *getWindow() = 0;
}
class QUIManager : public UIInterface
{
QWidget *getWindow() override {return m_widget;}
}
class XUIManager : public UIInterface
{
XWidget *getWindow() override {return m_widget;}
}
Except UIInterface should not know about QWidget. In some future version, the UIManager might be an XUIManager which returns a different type of window. If possible, I'd like to avoid returning std::any or void * followed by casting.
This pattern keeps showing up in my code, so I'm probably doing something wrong.
Edit based on comments:
My code is experimental, so although I'm using Qt as the UI for now, it's conceivable that may change, for example to use an immediate mode package, or in any case to separate the core logic from the UI. The core logic, may, for example, be accessed from just a console with no UI. Likewise, I'm using Qt's model/view and database classes.
Some examples:
The core needs to tell the UI to open and close windows. I've concluded in most cases that the core does not need to blindly shuffle naked UI pointers, so perhaps this use case is no longer that important.
The core needs to be able to glue database, model, and view together, without these latter three items knowing about each other, even though all three latter items may be specific to Qt or some other framework, or split up, such as using sqlite3 standalone and delegating model/view to Qt. For example, core needs to tell database interface to open a sqlite3 file, ask the modelcreator to create a model based on this, then pass model to UIManager to create the view. In no case does the core need to know specific types, and it would probably suffice to pass pointers around, but this seems like it's not the C++ way these days.
Although for now the track is C++, at some point the core itself might be implemented in a language better suited to the core algorithmic functions, eg Julia, Common Lisp, etc., which will introduce an impedance mismatch with Qt, so I'm trying my best to ensure the core can blindly call some high level functions while still serving as the central hub for the application.
Two options come in my mind, depending what fit better in your project:
1) Use a placeholder for return type:
class UIInterface
{
Widget* getWindow() = 0;
}
you can define in other file using Widget = QWidget. You can hange the alias or even implement your class Widget later and the whole UIInterface will not change. In this case you're just hiding the real type to the layout of your class.
2) You shoulde use a template class like
template<typename T>
class UIInterface
{
T* getWindow() = 0;
}
BUT there are downsides for No.2: you cannot use anymore UIInterface as interface without specifying T, and you're actually to state thatQWidget is the concrete type for T in your code.
Since you wrote "the interface might change in future" and not "I would create an interface regardless of the concrete widget type" I guess the option that fit you better is No.1

Usage of Composition or Virtual Inheritance in cases like Components of a GameObject

So development of games using the Object Oriented Paradigm in C++ generally involves the idea of GameObjects and their Components.
Now first and foremost, a GameObject would be a list of components like in the following:
class GameObject {
list<Component*> m_components;
Component* getComponent(component){}
}
Now of course, there are many other ways to implement the gameobject in a better and more efficient way, but that's irrelevant because my focus is going to be on the components. The way gameobjects is composed of components is the classic example of composition through the component based architecture as each component represents a behavior for the GameObject.
The components themselves could be composed of multiple "features" or behaviors that may be needed. For instance, we could have a component that relies on multiple other classes with behavior, such as clickables, drag and drop, and other classes.
Taking into account that each sub component does have everything necessary to function, they don't depend on calling their parent class constructor, and that concrete classes would implement a virtual method from one of the parent classes to perform actions as a result of a behavior occurring. I find it that using virtual inheritance in this case seems like a better solution than having another layer of composition. I'd end up with the following:
class Component {}
class clickable : virtual Component {
virtual onClick();
}
class draggable : virtual Component {
virtual onDrop();
}
Each class does what it needs without interfering with the base class. Each would add a functionality that can be inherited. all the concrete classes need to do is override the provided virtual. These can't be purely interfaces because each class has to do it's own stuff. A concrete class would look like:
class ConcreteComponent : public Component, public Clickable, public Dragable {}
Problems that need a solution:
1- static_casting is disabled, thus i'd be relying on dynamic_cast, and due to their costly nature, I am going to be forced to only call these during instantiation of a component and add pointers as member variables if any cross behavioral stuff is needed. Am I truly confined to this? would the direct attachment to the base component atleast alleviate part of the problem by allowing static casting to any concrete even if they have parent classes that are virtual base classes?
2- Speed-wise, how much worse would the reliance on virtual classes be than a straight forward inheritance implementation.
3- is there an actual viable composition based implementation on this sort of problem instead? isn't heavy reliance on composition a bad code smell especially when it's used on various levels?

Data abstraction that really allows isolating implementation from the user in C++

I hesitate to ask this question, because it's deceitfully simple one. Except I fail to see a solution.
I recently made an attempt to write a simple program that would be somewhat oblivious to what engine renders its UI.
Everything looks great on paper, but in fact, theory did not get me far.
Assume my tool cares to have an IWindow with IContainer that hosts an ILabel and IButton. That's 4 UI elements. Abstacting each one of these is a trivial task. I can create each of these elements with Qt, Gtk, motif - you name it.
I understand that in order for implementation (say, QtWindow with QtContainer) to work, the abstraction (IWindow along with IContainer) have to work, too: IWindow needs to be able to accept IContainer as its child: That requires either that
I can add any of the UI elements to container, or
all the UI elements inherit from a single parent
That is theory which perfectly solves the abstraction issue. Practice (or implementation) is a whole other story. In order to make implementation to work along with abstraction - the way I see it I can either
pollute the abstraction with ugly calls exposing the implementation (or giving hints about it) - killing the concept of abstraction, or
add casting from the abstraction to something that the implementation understands (dynamic_cast<>()).
add a global map pool of ISomething instances to UI specific elements (map<IElement*, QtElement*>()) which would be somewhat like casting, except done by myself.
All of these look ugly. I fail to see other alternatives here - is this where data abstraction concept actually fails? Is casting the only alternative here?
Edit
I have spent some time trying to come up with optimal solution and it seems that this is something that just can't be simply done with C++. Not without casting, and not with templates as they are.
The solution that I eventually came up with (after messing a lot with interfaces and how these are defined) looks as follows:
1. There needs to be a parametrized base interface that defines the calls
The base interface (let's call it TContainerBase for Containers and TElementBase for elements) specifies methods that are expected to be implemented by containers or elements. That part is simple.
The definition would need to look something along these lines:
template <typename Parent>
class TElementBase : public Parent {
virtual void DoSomething() = 0;
};
template <typename Parent>
class TContainerBase : public Parent {
virtual void AddElement(TElementBase<Parent>* element) = 0;
};
2. There needs to be a template that specifies inheritance.
That is where the first stage of separation (engine vs ui) comes. At this point it just wouldn't matter what type of backend is driving the rendering. And here's the interesting part: as I think about it, the only language successfully implementing this is Java. The template would have to look something along these lines:
General:
template<typename Engine>
class TContainer : public TContainerBase<Parent> {
void AddElement(TElementBase<Parent>* element) {
// ...
}
};
template<typename Engine>
class TElement : public TElementBase<Parent> {
void DoSomething() {
// ...
}
};
3. UI needs to be able to accept just TContainers or TElements
that is, it would have to ignore what these elements derive from. That's the second stage of separation; after all everything it cares about is the TElementBase and TContainerBase interfaces. In Java that has been solved with introduction of question mark. In my case, I could simply use in my UI:
TContainer<?> some_container;
TElement<?> some_element;
container.AddElement(&element);
There's no issues with virtual function calls in vtable, as they are exactly where the compiler would expect them to be. The only issue would be here ensuring that the template parameters are same in both cases. Assuming the backend is a single library - that would work just fine.
The three above steps would allow me to write my code disregarding backend entirely (and safely), while backends could implement just about anything there was a need for.
I tried this approach and it turns to be pretty sane. The only limitation was the compiler. Instantiating class and casting them back and forth here is counter-intuitive, but, unfortunately, necessary, mostly because with template inheritance you can't extract just the base class itself, that is, you can't say any of:
class IContainerBase {};
template <typename Parent>
class TContainerBase : public (IContainerBase : public Parent) {}
nor
class IContainerBase {};
template <typename Parent>
typedef class IContainerBase : public Parent TContainerBase;
(note that in all the above solutions it feels perfectly natural and sane just to rely on TElementBase and TContainerBase - and the generated code works perfectly fine if you cast TElementBase<Foo> to TElementBase<Bar> - so it's just language limitation).
Anyway, these final statements (typedef of class A inheriting from B and class X having base class A inheriting from B) are just rubbish in C++ (and would make the language harder than it already is), hence the only way out is to follow one of the supplied solutions, which I'm very grateful for.
Thank you for all help.
You're trying to use Object Orientation here. OO has a particular method of achieving generic code: by type erasure. The IWindow base class interface erases the exact type, which in your example would be a QtWindow. In C++ you can get back some erased type information via RTTI, i.e. dynamic_cast.
However, in C++ you can also use templates. Don't implement IWindow and QtWindow, but implement Window<Qt>. This allows you to state that Container<Foo> accepts a Window<Foo> for any possible Foo window library. The compiler will enforce this.
If I understand your question correctly, this is the kind of situation the Abstract Factory Pattern is intended to address.
The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part of the theme. The client doesn't know (or care) which concrete objects it gets from each of these internal factories, since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.
Creating a wrapper capable of abstracting libraries like Qt and Gtk doesn't seems a trivial tasks to me. But talking more generally about your design problem, maybe you could use templates to do the mapping between the abstract interface and a specific implementation. For example:
Abstract interface IWidget.h
template<typename BackendT>
class IWidget
{
public:
void doSomething()
{
backend.doSomething();
}
private:
BackendT backend;
};
Qt implementation QtWidget.h:
class QtWidget
{
public:
void doSomething()
{
// qt specifics here
cout << "qt widget" << endl;
}
};
Gtk implementation GtkWidget.h:
class GtkWidget
{
public:
void doSomething()
{
// gtk specifics here
cout << "gtk widget" << endl;
}
};
Qt backend QtBackend.h:
#include "QtWidget.h"
// include all the other gtk classes you implemented...
#include "IWidget.h"
typedef IWidget<QtWidget> Widget;
// map all the other classes...
Gtk backend GtkBackend.h:
#include "GtkWidget.h"
// include all the other gtk classes you implemented...
#include "IWidget.h"
typedef IWidget<GtkWidget> Widget;
// map all the other classes...
Application:
// Choose the backend here:
#include "QtBackend.h"
int main()
{
Widget* w = new Widget();
w->doSomething();
return 0;
}

can an abstract class inherit from a "normal" class?

I am looking for a useful example of multiple inheritance in C++ and found an example for Window-creation here: A use for multiple inheritance? and modified it a bit. It conceptually looks like this:
class Window
class Skinable // abstract
class Draggable // abstract
class DraggableSkinnableWindow : Window, Draggable, Skinnable
I think this is supposed to be a good example where MI makes sense. Since it doesn't make sense to implement a class of Skinable, it should be defined abstract.
Now: How would this look like if I would not use the concept of MI.
I would have used a simple hierarchical structure like this:
class Window
class Dragable : public Window
class Skinable : public Dragable
class DraggableSkinnableWindow : Skinnable
I still want Dragable and Skinable to be abstract as well but is that even possible? Is the second example even a good solution for the same context but not using MI?
Thank you in advance!
While your example is a solid use case for multiple inheritance, I disagree with the assertion that it does not make sense for Skinnable to have an implementation. Rather, as #devianfan alluded to in his comment, your single inheritance alternative fails to model the conceptual taxonomy.
It is about cross axial classifications. A window is both skinabble and draggable but neither of these qualities are codependent.
Consider that, as suggested by your example domain, your application code consists of a collection of graphical user interface elements. You might want to perform perform operations on subgroups of them based on their capabilities. For example you might manipulate the appearance of all skinnable elements based on some customization. On the other hand, there are probably elements of your GUI which are draggable and should be notified on certain user input events. A window is a good example of something which falls into both categories.
I would probably go like this
class Window
class Draggable : public virtual Window
class Skinnable : public virtual Window
class DraggableSkinnableWindow : Draggable, Skinnable
And provide default implementation in the pure virtual methods contained in Draggabel and Skinnable separately
class Draggable : public virtual Window {
virtual void aMethod() = 0;
void aMethodDefaultImplementation() = { //...// };
}
then inside DraggableSkinnable you have two options:
virtual void aMethod() = { aMethodDefaultImplementation() };
or
virtual void aMethod() = {// ...non-default implementation... //};
This has the benefit of providing a default implementation if you need one (as if aMethod was not pure virtual) but forcing you to ask for that explicitly (because it is purely virtual).
I think this is supposed to be a good example where MI makes sense.
It does, at long as Window, Draggable, Skinnable do not share common ancestor, at least other than pure abstract, otherwise you would need virtual inheritance.
Since it doesn't make sense to implement a class of Skinable, it should be defined abstract.
It can make sense, for example defining a property skin + setters and getters. You seem to be confusing abstract classes and pure abstract classes. Abstract classes have at least one pure virtual function, which means you cannot instantiate them. Pure abstract classes do not have any implementation of any method, they contain only pure virtual functions, and are often used as a realization interface concept in c++.
How would this look like if I would not use the concept of MI. Is the second example even a good solution for the same context but not using MI?
You cannot do it properly. c++ does not differentiate between classes and interfaces (as it does not provide such concept on language level). It is the same as stripping java or c# of interfaces. It would be possible if you provided all the compounds by hand i.e. Skinnable, Draggable bases, would produce SkinnableDraggable and/or DraggableSkinnable (which would probably be equivalent) dervided classes. This is quite a killer.
Your example, as others mentioned completely mixes unrelated concepts. E.g. Your Draggables and Skinnables must be Windowses. This is not obvious, and certainly not correct in general.

Can someone explain the benefits of polymorphism?

So I understand pretty much how it works, but I just can't grasp what makes it useful. You still have to define all the separate functions, you still have to create an instance of each object, so why not just call the function from that object vs creating the object, creating a pointer to the parent object and passing the derived objects reference, just to call a function? I don't understand the benefits of taking this extra step.
Why do this:
class Parent
{
virtual void function(){};
};
class Derived : public Parent
{
void function()
{
cout << "derived";
}
};
int main()
{
Derived foo;
Parent* bar = &foo;
bar->function();
return -3234324;
}
vs this:
class Parent
{
virtual void function(){};
};
class Derived : public Parent
{
void function()
{
cout << "derived";
}
};
int main()
{
Derived foo;
foo.function();
return -3234324;
}
They do exactly the same thing right? Only one uses more memory and more confusion as far as I can tell.
Both your examples do the same thing but in different ways.
The first example calls function() by using Static binding while the second calls it using Dynamic Binding.
In first case the compiler precisely knows which function to call at compilation time itself, while in second case the decision as to which function should be called is made at run-time depending on the type of object which is pointed by the Base class pointer.
What is the advantage?
The advantage is more generic and loosely coupled code.
Imagine a class hierarchy as follows:
The calling code which uses these classes, will be like:
Shape *basep[] = { &line_obj, &tri_obj,
&rect_obj, &cir_obj};
for (i = 0; i < NO_PICTURES; i++)
basep[i] -> Draw ();
Where, line_obj, tri_obj etc are objects of the concrete Shape classes Line, Triangle and so on, and they are stored in a array of pointers of the type of more generalized base class Shape.
This gives the additional flexibility and loose coupling that if you need to add another concrete shape class say Rhombus, the calling code does not have to change much, because it refers to all concrete shapes with a pointer to Base class Shape. You only have to make the Base class pointer point to the new concrete class.
At the sametime the calling code can call appropriate methods of those classes because the Draw() method would be virtual in these classes and the method to call will be decided at run-time depending on what object the base class pointer points to.
The above is an good example of applying Open Closed Principle of the famous SOLID design principles.
Say you want someone to show up for work. You don't know whether they need to take a car, take a bus, walk, or what. You just want them to show up for work. With polymorphism, you just tell them to show up for work and they do. Without polymorphism, you have to figure out how they need to get to work and direct them to that process.
Now say some people start taking a Segway to work. Without polymorphism, every piece of code that tells someone to come to work has to learn this new way to get to work and how to figure out who gets to work that way and how to tell them to do it. With polymorphism, you put that code in one place, in the implementation of the Segway-rider, and all the code that tells people to go to work tells Segway-riders to take their Segways, even though it has no idea that this is what it's doing.
There are many real-world programming analogies. Say you need to tell someone that there's a problem they need to investigate. Their preferred contact mechanism might be email, or it might be an instant message. Maybe it's an SMS message. With a polymorphic notification method, you can add a new notification mechanism without having to change every bit of code that might ever need to use it.
polymorphism is great if you have a list/array of object which share a common ancestor and you wich to do some common thing with them, or you have an overridden method. The example I learnt the concept from, use shapes as and overriding the draw method. They all do different things, but they're all a 'shape' and can all be drawn. Your example doesn't really do anything useful to warrant using polymorphism
A good example of useful polymorphism is the .NET Stream class. It has many implementations such as "FileStream", "MemoryStream", "GZipStream", etcetera. An algorithm that uses "Stream" instead of "FileStream" can be reused on any of the other stream types with little or no modification.
There are countless examples of nice uses of polymorphism. Consider as an example a class that represents GUI widgets. The most base classs would have something like:
class BaseWidget
{
...
virtual void draw() = 0;
...
};
That is a pure virtual function. It means that ALL the class that inherit the Base will need to implement it. And ofcourse all widgets in a GUI need to draw themselves, right? So that's why you would need a base class with all of the functions that are common for all GUI widgets to be defined as pure virtuals because then in any child you will do like that:
class ChildWidget
{
...
void draw()
{
//draw this widget using the knowledge provided by this child class
}
};
class ChildWidget2
{
...
void draw()
{
//draw this widget using the knowledge provided by this child class
}
};
Then in your code you need not care about checking what kind of widget it is that you are drawing. The responsibility of knowing how to draw itself lies with the widget (the object) and not with you. So you can do something like that in your main loop:
for(int i = 0; i < numberOfWidgets; i++)
{
widgetsArray[i].draw();
}
And the above would draw all the widgets no matter if they are of ChildWidget1, ChildWidget2, TextBox, Button type.
Hope that it helps to understand the benefits of polymorphism a bit.
Reuse, generalisation and extensibility.
I may have an abstract class hierarchy like this: Vehicle > Car. I can then simply derive from Car to implement concrete types SaloonCar, CoupeCar etc. I implement common code in the abstract base classes. I may have also built some other code that is coupled with Car. My SaloonCar and CoupeCar are both Cars so I can pass them to this client code without alteration.
Now consider that I may have an interface; IInternalCombustionEngine and a class coupled with with this, say Garage (contrived I know, stay with me). I can implement this interface on classes defined in separate class hierarchies. E.G.
public abstract class Vehicle {..}
public abstract class Bus : Vehicle, IPassengerVehicle, IHydrogenPowerSource, IElectricMotor {..}
public abstract class Car : Vehicle {..}
public class FordCortina : Car, IInternalCombustionEngine, IPassengerVehicle {..}
public class FormulaOneCar : Car, IInternalCombustionEngine {..}
public abstract class PowerTool {..}
public class ChainSaw : PowerTool, IInternalCombustionEngine {..}
public class DomesticDrill : PowerTool, IElectricMotor {..}
So, I can now state that an object instance of FordCortina is a Vehicle, it's a Car, it's an IInternalCombustionEngine (ok contrived again, but you get the point) and it's also a passenger vehicle. This is a powerful construct.
The poly in polymorphic means more than one. In other words, polymorphism is not relevant unless there is more than one derived function.
In this example, I have two derived functions. One of them is selected based on the mode variable. Notice that the agnostic_function() doesn't know which one was selected. Nevertheless, it calls the correct version of function().
So the point of polymorphism is that most of your code doesn't need to know which derived class is being used. The specific selection of which class to instantiate can be localized to a single point in the code. This makes the code much cleaner and easier to develop and maintain.
#include <iostream>
using namespace std;
class Parent
{
public:
virtual void function() const {};
};
class Derived1 : public Parent
{
void function() const { cout << "derived1"; }
};
class Derived2 : public Parent
{
void function() const { cout << "derived2"; }
};
void agnostic_function( Parent const & bar )
{
bar.function();
}
int main()
{
int mode = 1;
agnostic_function
(
(mode==1)
? static_cast<Parent const &>(Derived1())
: static_cast<Parent const &>(Derived2())
);
}
Polymorphism is One of the principles OOP. With polymorphism you can choose several behavior in runtime. In your sample, you have a implementation of Parent, if you have more implementation, you can choose one by parameters in runtime. polymorphism help for decoupling layers of application. in your sample of third part use this structers then it see Parent interface only and don't know implementation in runtime so third party independ of implementations of Parent interface. You can see Dependency Injection pattern also for better desing.
Just one more point to add. Polymorphism is required to implement run-time plug-ins. It is possible to add functionality to a program at run-time. In C++, the derived classes can be implemented as shared object libraries. The run time system can be programmed to look at a library directory, and if a new shared object appears, it links it in and can start to call it. This can also be done in Python.
Let's say that my School class has a educate() method. This method accepts only people who can learn. They have different styles of learning. Someone grasps, someone just mugs it up, etc.
Now lets say I have boys, girls, dogs, and cats around the School class. If School wants to educate them, I would have to write different methods for the different objects, under School.
Instead, the different people Objects (boys,girls , cats..) implement the Ilearnable interface. Then, the School class does not have to worry about what it has to educate.
School will just have to write a
public void Educate (ILearnable anyone)
method.
I have written cats and dogs because they might want to visit different type of school. As long as it is certain type of school (PetSchool : School) and they can Learn, they can be educated.
So it saves multiple methods that have the same implementation but different input types
The implementation matches the real life scenes and so it's easy for design purposes
We can concentrate on part of the class and ignore everything else.
Extension of the class (e.g. After years of education you come to know, hey, all those people around the School must go through GoGreen program where everyone must plant a tree in the same way. Here if you had a base class of all those people as abstract LivingBeings, we can add a method to call PlantTree and write code in PlantTree. Nobody needs to write code in their Class body as they inherit from the LivingBeings class, and just typecasting them to PlantTree will make sure they can plant trees).