C++ make an object whose type is an abstract class

226 views Asked by At

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!

2

There are 2 answers

0
phantom On BEST ANSWER

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() { }
0
nsamsonau On

In systems like that, types like Label, CheckBox, TextBox are separate classes derived from Component class. So, if you want a similar behavior, you need to implement new classes and derive them from Component class. You are also required to override the virtual functions.