Jump to content
  • Advertisement
Sign in to follow this  
DMINATOR

C++ array of derived classes . Possible ?

This topic is 4851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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".

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.



Share this post


Link to post
Share on other sites
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 properties
class Base
{
public:
int idea;

Base()
{
idea = 1;
}

~Base()
{
idea = 10;
}
};



//derived-class from base
//holds additional properties
class Test1 : public Base
{

public:

//additional var
int var1;

Test1()
{
var1 = 1337;
}

~Test1()
{
var1 = 0;
}
};



//derived-class from base
//holds additional properties
class 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.

Share this post


Link to post
Share on other sites
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-class
class 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-class
class 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 base
class 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

Share this post


Link to post
Share on other sites
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 memory


pElement = 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 object

ArrayOfGuiElements[1]->Render(); //calls the EditBox Render function, as it points to a button object

delete 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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!