You should try to avoid void pointers in C++ where possible, as you have lost the type information and type safety which C++ provides. It is hard to recommend a better design from your last rather.. abstract example. [smile]
But returning to the GUI elements, there are many possible ways to implement it. Perhaps the easiest to understand is just a spinoff of the typical shapes heirarchy provided in a lot of beginners books.
First of all you would have a base class called GuiElement, which defines a
pure virtual interface, which is used by all gui elements. This may include a render function, or a clicked function.
class GuiElement{public:virtual ~GuiElement(){}virtual void Render() = 0;virtual void Clicked() = 0;};
Note the
virtual destructor, this is important if you are planning on deleting instances that are of a type derived from GuiElement, via a GuiElement pointer.
You would then go on to derive classes from this GuiElement class for each type of GUI object you wish to implement. The examples you gave were buttons and edit boxes.
class Button : public GuiElement{virtual void Render(){ /*render the button in here */}virtual void Clicked(){ /*deal with the button click event here*/}};class EditBox: public GuiElement{virtual void Render(){ /*render the EditBox in here */}virtual void Clicked(){ /*deal with the EditBox click event here */}};
Here we have implemented the virtual infterface from GuiElement in two new classes, EditBox and Button, which presumably will implement the functions in different ways.
The next part is using these classes polymorphically through a base class pointer,
GuiElement * pElement = new EditBox;...pElement->Render(); //calls the Render function implemented in the EditBox class.pElement->Clicked();//calls the Clicked function implemented in the EditBox class.delete pElement; //calls the EditBox destructor and releases memorypElement = new Button;...pElement->Render(); //calls the Render function implemented in the Button class.pElement->Clicked();//calls the Clicked function implemented in the Button class.delete pElement; //calls the Button destructor and releases memory
That is an example of basic dynamic polymorphism. The behaviour of the function call on a GuiElement pointer depends on the derived type of the object to which the pointer points.
We could implement this in exactly the same manner with an array of pointers, which i think answers your initial question.
GuiElement * ArrayOfGuiElements[10];ArrayOfGuiElements[0] = new Button;ArrayOfGuiElements[1] = new EditBox;ArrayOfGuiElements[0]->Render(); //calls the Button Render function, as it points to a button objectArrayOfGuiElements[1]->Render(); //calls the EditBox Render function, as it points to a button objectdelete ArrayOfGuiElements[0];delete ArrayOfGuiElements[1];
This is probably the easiest way to achieve this, though there are others, such as static polymorpishm, which involves the use of things like policy and trait classes with templates. You might also want to look into
smart pointers, as they help making the memory management things easier in examples like this.