At the risk of being shot down I ask this question
I am trying to make a dynamic program that arrange objects according to the presets in a specific class, only created for that purpose. I, however, wish to make the function able to take different types of objects (in this case Button & Hyperlink & Label) and arrange them according to their types. I have therefore created an Array which takes Component -objects and are passing these to the function doing the arrangement of objects. In this way I am sure to achieve a consistent layout no matter the types or amount of objects I send to the function.
SO
I have 3 questions.
Is it legal to do this type of “generic” passing of Component-child objects to an Array taking Component objects? (like Button & Hyperlink & Label which all inherent from the Component class)
Is it legal to put an Array<Component> inside of another Array ? like so: Array<Array<Component>> I would like to be able to pass an Array of Array<Component>-objects to enable my function to arrange chunks of objects. Like 3 blocks of objects: 1 block with 3 objects, 1 block with 5 objects, 1 block with 2 objects… you get the idea.
If all of this IS legal, and I just don’t have the overview to comprehend my own code just yet -How then, do you access the types of the objects in the Array<Component> ? I have tried looping through the Array using the typeid(singleBlockArray[i]).name()-method, but they all print out class juce::Component.
As you may have guessed I have had some success doing this Array<Array<Component>>-kinda’ thing, but I very often get these weird errors which points to places in the Juce_Array-files, which gets me thinking that this practice might be wrong all together.
Some code for clarification:
// ArrangingClass.h:
class ArrangingClass
{
public:
ArrangingClass(Array<Array<Component>> multipleBlocksArray);
};
//ArrangingClass.cpp:
ArrangingClass::ArrangingClass(Array<Array<Component>> multipleBlocksArray)
{
for (int i = 0; i < multipleBlocksArray.size(); i++)
{
DBG("This is object-block number: " + i); // For printing in Visual Studio
Array<Component> singleBlockArray = multipleBlocksArray[i];
for (int i = 0; i < singleBlockArray.size(); i++)
{
DBG("This object is of type: " + typeid(singleBlockArray[i]).name()); // For printing in Visual Studio
// Do some arranging magic
}
}
}
You need to use Component* instead of Component as the array element. Or rather ScopedPointer< Component > or similar in order to not leak memory. Also instead of typeid() you might find dynamic_cast more useful.
Yes, that’s also possible. See @xenakios answer, he was faster
One option is dynamic_cast, or the more OO-version would be, to create an interface that all your three components conform to. So the Array will hold objects of type of your interface:
class MyGuiInterface {
public:
void foo() = 0;
}
class MySlider : public Slider, public MyGuiInterface
{
public:
void foo() {
setValue (100); // as example
}
}
class MyHyperlink : public HyperlinkButton, public MyGuiInterface
{
public:
void foo() {
setUrl ("http://juce.com"); // as example
}
}
OwnedArray<OwnedArray<MyGuiInterface> > multipleBlocksArray;
Now all objects in multipleBlocksArray will understand the method foo(), and you don’t need to figure out which type they are.
again, here is dynamic_cast:
if (Button* button = dynamic_cast<Button*>(singleBlockArray[i])) {
// use button
}
Glad to hear I weren’t completely off tracks. Visual Studios just keeps bugging me with strange errors that disappear when I clean the solution I have also changed my code to be Component*
The dynamic_cast looks like something I might enjoy, and thanks @daniel for the elaborate explanation Those sort of explicit examples are the best!