C++ array of derived classes . Possible ?

Started by
15 comments, last by Zahlman 18 years, 8 months ago
Hi I am trying something new with C++, I have some experience with Java and C#, when using derived classes. But I don't quite know, is this possible to do with C++. I am trying to make something like GUI, with components, as a reference I would like to use C# winForms, with their handy and easy way to work with GUI components like (If I remember it right):
Quote: Form1.Components.Add(button1);
So if I have many derived classes like buttons, editbox , label and so on. How would it possible to use them ? for example :
Quote: button button1; label label1; window1.Components.Add(button1); window1.Components.Add(label1);
so how should the window1.components ? be structured. Well I hope anyone can figure out what I was trying to say, and at least point me out to the right direction, which I would really appreciate. Thanks.
Advertisement
Try to avoid creating arrays of polymorphic objects in C++, because pointer arithmetic is used to index through the array, and if the objects are of different size, this will result in incorrect addresses for objects in the array.
If they're not going to be all of the same type (i.e. it just happens that this one type is derived from something else), then you will need to add a layer of indirection (i.e. store pointer instead, which Java is doing for you automatically). [google] "object slicing".
You would make a base class, let's call it Window, and derive your controls from it. Then you can have your Components be an array of Window* and everything is fine.
Well I am probably going to use linked list for this purpose.

The Window class is going to have a pointer to the first component in the list like:

Quote:
Component *first;


now each component should have properties of base component class and additional properties , also it has a pointer to the next component. NULL indicates no next component.

The problem is I don't know how to make this Component pointer.


2 gtdelarosa
Quote:
Try to avoid creating arrays of polymorphic objects in C++, because pointer arithmetic is used to index through the array, and if the objects are of different size, this will result in incorrect addresses for objects in the array.

Yes this is exactly what I was trying to avoid, because components are going to be different in size. So I decided to use linked list instead.


2 Zahlman
Quote:
If they're not going to be all of the same type (i.e. it just happens that this one type is derived from something else), then you will need to add a layer of indirection (i.e. store pointer instead, which Java is doing for you automatically). "object slicing".

Ok I haven't heard of this way. What do you mean by storing the pointer ? Pointer to what exactly ?


2 Konfusius
Quote:
You would make a base class, let's call it Window, and derive your controls from it. Then you can have your Components be an array of Window* and everything is fine.

Ok I am going to try this one.


Thanks everyone, if I am going to stuck at this again, il let you know.



Well after some few tryes I came up with this way. I am using void* pointer for this:

#include <stdio.h>//base-class//holds basic propertiesclass Base{public:	int idea;	Base()    {		idea = 1;	}	~Base()	{		idea = 10;	}};//derived-class from base//holds additional propertiesclass Test1 : public Base{public:	//additional var	int var1;	Test1()	{	 var1 = 1337;	}	~Test1()	{	 var1 = 0;	}};//derived-class from base//holds additional propertiesclass Test2 : public Base{public:	int var2;	Test2()	{	 var2 = 31337;	}	~Test2()	{	 var2 = 0;	}};int main(){	//here are classes with different 	//additional variables	Test1 test1;	Test2 test2;	//let's create base class to use as reference	void *pbase = NULL;	//let's try first class 	pbase = &test1;	//now let's output default properties of class	printf("pbase.var1 = %d\n",((Test1*)pbase)->var1);	//let's try second class 	pbase = &test2;	//now let's output default properties of class	printf("pbase.var2 = %d\n",((Test2*)pbase)->var2);	return 0;}


It works good for now.
You don't need to (and shouldn't!) use a void * there. What you can do is actually assign the derived classes to a base class pointer. You can then use a dynamic_cast to get back the derived pointer.

So, here's an updated version of your code:
#include <iostream>//base-classclass Base{public:	Base():idea(1) {} //This is called an initialization list	~Base()	{		//idea = 10; No need to do this, you can't use it after the destructor has been called	}protected: //Enable derived classes to use it, but no one else	int idea;};//derived-classclass Test1 : public Base{public:	Test1():var1(1337) {}	~Test1() {}	int GetVar() const {return var1;}private: //Only this class can see it	//additional var	int var1;};//derived-class from baseclass Test2 : public Base{public:	Test2():var2(31337) {}	~Test2() {}	int GetVar() const {return var2;}private:	int var2;};int main(){	//If you want to store these in an array, as you first posted, you will need to allocate them using new (and then clean them up with delete	Test1 test1;	Test2 test2;	Base * pBase = &test1; //This is perfectly legal	//Normally, if you use dynamic_cast, you should check if it converted ok (i.e. it didn't return 0)	std::cout << "pBase.var1 = " << dynamic_cast<Test1 *>(pBase)->var1 << std::endl;	//Reassign pBase	pBase = &test2;	std::cout << "pBase.var2 = " << dynamic_cast<Test2 *>(pBase)->var2 << std::endl;	return 0;}


Here's some info on dynamic_cast

HTH
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.
Thanks for your good answer with source :). I am still learning C++ , especially these OOP features that are making it so hard but flexible.

2 desertcube. Thanks for your suggestion I haven't used dynamic_cast before. Il probably going to use it later in my programs :)

I got the idea how to make it work, although I have one more question, I need before starting the coding:

How can I change virtual function body ?

From your example Mxz
class Button : public GuiElement{virtual void Render(){ /*render the button in here */}virtual void Clicked(){ /*deal with the button click event here*/}};


The clicked is stored inside the class. The thing I want to do is to specify unique actions when button is clicked. The similar way Borland C++ and C# are working, although I can't figure out how to implement it myself.

The ideal way would be :
Button button1 = new Button;//that's not probably even possible void button1::Clicked(){  //my code for this button}


So is there a way I can possibly use something similar ?

Quote:
P.S. One more question. The reason why I used void* pointer , is that each derived class has a unique variable, so other derived class doesn't has it.

For example:

If I have 2 components - ListBox and Winsock. They each have a unque procedures and functions, winsock component for example has: ->Connect() , ->Diconnect(). The ListBox: ->AddElement(stirng "element"), ->DeleteElementByName(string "element").

So this got me confused , I probably going to need to use dynamic_cast then ? Or not ? I think I am even more confused now :)
Quote:Original post by DMINATOR
The clicked is stored inside the class. The thing I want to do is to specify unique actions when button is clicked. The similar way Borland C++ and C# are working, although I can't figure out how to implement it myself.

The ideal way would be :
*** Source Snippet Removed ***

So is there a way I can possibly use something similar ?

You need to looko into function pointers (here's an excellent example from that site).

However, if you want to use call backs to member function, I recommend the use of something like boost.

This topic is closed to new replies.

Advertisement