I am trying to make a system like Java's swing
, where you have a window, and that window has multiple components, such as Labels (text/images), Text Boxes, Check Boxes, etc. The way swing
works is that there is a Component
class, which is abstract, which has an abstract paint method, which draws the component, and some other methods. The actual window (JFrame
) has a list (of sorts) of all of the components in the window. These components' actual types are unknown, but they all extend the Component
class.
My Window
class:
class Window {
public:
...
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr> T addComponent(T component);
private:
...
std::vector<Component> components;
...
};
Component
:
class Component {
public:
...
virtual void paintComponent() = 0;
...
};
Somewhere along the line, this code is called:
for each (Component c in components) {
c.paintComponent();
}
However, I cannot make an object of type Component
, because it is abstract, although the actual objects would be other types that extend Component
and have their own paintComponent()
method. For methods (Window::addComponent()
), I can use
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr> T
however, this does not work for variables.
So, my question is, How do I make an object of an abstract type, i.e. how do I make a Component
object (or an object that extends Component, but whose actual type is unknown)?
Thanks in advance!
You can't instantiate a type of a abstract class. You have to refer to it through a pointer. This will force you to do manual memory management. So using a smart pointer like shared_ptr
or unique_ptr
can help reduce headaches. Using pointers would make your vector look like this
std::vector<Component*> components;
// ^ Indicates pointer
and then in your loop you would call it like this
p->paintComponent();
This way you can use Component
for any type that derives from it.
Also, if Component is going to be used like this it should have a virtual destructor. This will make sure that the correct destructor is called if it deleted through a pointer to a Component
. This would make the destructor declaration look like this
virtual ~Component() { }