Nested data structure where children inherit data from parent - c++

I'm trying to create a nested data structure that is many layers deep where every "child" can access data from their parent/grandparent/etc...
for example take these data structures:
struct GrandChild {
int someGrandChildData;
};
struct Child {
int someChildData;
std::vector<GrandChild> vgrandChild;
};
struct Parent {
int someParentData;
std::vector<Child> vchild;
};
struct GrandParent {
int someGrandParentData;
std::vector<Parent> vparent;
};
The way I'd like to access the data would be like this:
void main()
{
// create and fill in the data
GrandParent gp;
for (int pNum = 0; pNum < 3; pNum++)
{
gp.vparent.push_back(Parent());
for (int cNum = 0; cNum < 3; cNum++)
{
gp.vparent[pNum].vchild.push_back(Child());
for (int gcNum = 0; gcNum < 3; gcNum++)
{
gp.vparent[pNum].vchild[cNum].vgrandChild.push_back(GrandChild());
// call function and ONLY pass a GrandChild
func(gp.vparent[pNum].vchild[cNum].vgrandChild[gcNum]);
}
}
}
}
void func(GrandChild &gc)
{
int result = gc.someGrandChildData;
// no need to pass GrandParent, Parent, or Child because
// GrandChild can access all of the data from them
result += gc.someChildData; // <<-- how can I achieve something like this
result += gc.someParentData; // <<-- how can I achieve something like this
result += gc.someGrandParentData; // <<-- how can I achieve something like this
}
I'm trying to do this because I have structures with many data members at each nesting layer and when I call functions it's extremely annoying to have to pass large numbers of arguments into each function call and becomes a mess to keep organized.
Any help would be greatly appreciated.

You could do it by keeping track of the Parent of every person(let's call it Node). So, for every Node, create an object of its direct Parent inside of it and do that for every layer (GrandChild, Child, Parent.. etc).
So each GrandChild will have a Child object, each Child will have a Parent object and each Parent will have a GrandParent object.
Then you will be able to do something like this:
void func(GrandChild &gc)
{
int DataFromTheGranChild = gc.DataFromGrandChild;
int DataFromTheChild = gc.Child.DataFromChild;
int DataFromTheParent = gc.Child.Parent.DataFromParent;
int DataFromTheGradParent = gc.Child.Parent.GrandParent.DataFromGrandParent;
//..
}

You could try to only use one type of struct.
struct Entity{
int Data;
Entity* Child;
Entity* Parent;
};

Related

C++ pass derived struct to method expecting the super struct

I am trying to create a menu library for arduino with C++ and OOP.
I have a struct called:
struct MenuItem {
int position;
String name;
MenuItem(int position, String name) : position(position), name(name) { };
};
And I have a derived struct called:
struct SpecificMenuItem : MenuItem {
int count;
SpecificMenuItem(int position, String name, int count) : MenuItem(position, name) , count(count) { };
};
How can I pass an array of the SpecificMenuItem structs to a method that expects an array of MenuItem? The idea here is that all the derived structs from MenuItem should have position and name, so that a simple list can be rendered out with the following method from the Menu class:
Menu::Menu() {
}
void Menu::setMenuItems(MenuItem *menuItems) {
this->mMenuItems = menuItems;
}
void Menu::render(void) {
for (int j = 0; j < this->mMenuItemSize; j++) {
Serial.println(this->mMenuItems[j].name);
}
}
The header file for specific_menu.h:
class SpecificMenu : public Menu {
struct SpecificMenuItem mSpecificMenuItem[2] = {
{1, "Name", 3},
{2, "Name 2", 4}
};
public:
SpecificMenu();
};
The cpp file for specific_menu.cpp:
SpecificMenu::SpecificMenu() : Menu() {
this->setMenuItems(this->mSpecificMenuItem);
this->setMenuItemsSize(2);
}
The issue right now is that having the extra count member in the SpecificMenuItem struct is causing the program to crash, however the program runs fine if I remove the count member, but I think this is just a fluke that it works. Would love to get some pointers on how to get the above to work.
Cheers!
You cannot pass an array of SpecificMenuItem to a method waiting for an array of MenuItem, even if SpecificMenuItem inherits from MenuItem.
One possible way would be to remove the setMenuItems methods and makes use of polymorphism to access the size and the items of the menu:
class Menu {
protected:
virtual size_t size () const = 0;
virtual MenuItem& operator[] (size_t) = 0;
};
class SpecificMenu : public Menu {
SpecificMenuItem mSpecificMenuItem[2] = {
{1, "Name", 3},
{2, "Name 2", 4}
};
protected:
virtual size_t size () const { return 2; }
virtual const MenuItem& at (size_t i) const {
return mSpecificMenuItem[i];
}
public:
SpecificMenu();
};
And then use these method in Menu::render:
void Menu::render(void) {
for (int j = 0; j < this->size(); j++) {
Serial.println(this->at(j).name);
}
}
This is making your Menu acts as a (abstract) container of "MenuItem&".
You'd better declare something like:
typedef std::list<MenuItem *> MenuItemArray;
Then you can access you base classes by pointer.
void
Menu::setMenuItems(const MenuItemArray& menuItems)
{
this->mMenuItems = menuItems;
}
void
Menu::render(void)
{
for (int j = 0; j < this->mMenuItems.size(); j++) {
Serial.println(this->mMenuItems[j]->name);
}
}
Afterward, if you need to access a SpecificMenuItem element:
...
SpecificMenuItem *specificItem = dynamic_cast<SpecificMenuItem *>(mMenuItems[i]);
if (specificItem) {
...
}
The solution you initialy wrote rather looks like a C solution, not C++ IMHO.
Have fun.
Your problem is, you can't put different structs/classes in same array, as they have different sizes. Consider making array of pointers, that point to objects of base class, as they can point to derived as well. Like
typedef MenuItem * MenuItemPtr;
typedef MenuItemPtr * MenuItemPtrArray;
MenuItemPtrArray myArr= new MenuItemPtr[2];
myArr[1] = new MenuItem(/*...*/);
myArr[2] = new SpecificMenuItem(/*....*/);
Of course, you can use std::list or other collectionas #Holt suggested in his answer, and it would be better solution. But I suppose you don't have it as you write for arduino, which has no stl

Passing an array of Child objects to a function that accepts Parent*

I am working on an embedded platform with limited capabilities, so vectors/STL are not available.
This may be a trivial problem, but I do not have much experience in C++ (only C and C#, which may make me blind to an obvious c++ way to do it).
Consider the following example:
class Parent {
};
class Child : public Parent {
};
void Test(Parent* parents, uint8_t parentCount) {
// Accessing parent[x] is problematic when 'parents' contains a derived type
}
int main() {
// This is OK
Parent parents[3];
Test(parents, 3);
// This causes problems
Child children[3];
Test(children, 3);
return 0;
}
Obviously it is problematic to iterate over parents in Test(), if a pointer to an array of derived classes is provided, because the memory footprint of Parent is assumed during the iteration.
The only solution I see is to pass an array of pointers of type Parent (Parent** parents), but that seems cumbersome. Is there some C++ mechanism I am not aware of, like passing the array as a reference or something?
You could use this approach:
template <class T>
void Test(T* parents, uint8_t parentCount) {
// Code that accesses parent[x]
}
and then use it like this:
int main() {
Parent parents[3];
Test(parents, 3);
Child children[3];
Test(children, 3);
return 0;
}
If template is not an option and when the user of Test can not depend on Child and can't even know it's size, then you can use an array of pointers:
void Test(Parent** parents, uint8_t parentCount);
int main() {
Child children[n];
Child* pointers[n];
for(int i = 0; i < n; i++)
pointers[i] = &children[i];
Test(pointers);
}
Note that in this trivial example, we do know the size of the object whose pointers we pass, but in general, we may not be able to make that assumption for all users of Test.
If you can't use templates, you can do this:
class Parent {
};
class Child : public Parent {
};
void Test(Parent* parents, uint8_t parentCount, uint16_t parentSize) {
for (uint8_t ii = 0; ii < parentCount; ++ii) {
void* parentvoid = reinterpret_cast<char*>(parents) + ii * parentSize;
Parent* parent = parentvoid;
}
}
int main() {
Parent parents[3];
Test(parents, 3, sizeof(parents[0]));
Child children[3];
Test(children, 3, sizeof(children[0]));
}

C++: Cloning and overloading with multiple inheritance

This is a follow-up to this question. Someone asked about a minimal example, but I found it impossible to condense it all into something working. I still have issues, so I hope that by giving a bit more structure I can get some idea of what I am doing wrong or what I should be doing.
The classes I use form a tree structure, like this:
struct Base
{
/* nodeType is a number uniquely assigned to each concrete class */
int nodeType;
int numberOfA;
int numberOfB;
int NumberOfC;
int numberOfD;
AdvancedA** A_array;
AdvancedB** B_array;
AdvancedC** C_array;
Intermediate1** D_array;
virtual Base clone() = 0;
}
struct Intermediate1 : Base
{
}
struct Intermediate2 : Base
{
}
struct Advanced_A : Intermediate1
{
/* There might be different signatures since arguments might be
* real-valued, complex, or even matrices
*/
virtual double compute(signature 1);
virtual double compute(signature 2);
}
struct Advanced_B : Intermediate1
{
virtual std::complex compute(signature 1);
virtual std::complex compute(signature 2);
}
struct Advanced_C : Intermediate2
{
virtual matrix compute(signature 1);
//for example; definition of matrix class is not shown
}
struct Instance_A1 : Advanced_A
{
}
struct Instance_A2 : Advanced_A
{
}
...
struct Instance_B1 : Advanced_B
{
}
...
struct Instance_C1 : Advanced_C
{
}
...
I use these objects to build expression trees, which can evaluate to different types, corresponding to the three Advanced types. (Think of them as real-valued, complex-valued and matrix-valued expressions.) Because I need to evaluate the expressions, I have created three different types of expression trees, as follows.
struct BasicTree
{
virtual void cloneTree();
}
struct TreeType_A : BasicTree
{
Advanced_A* root;
}
struct TreeType_B : BasicTree
{
Advanced_B* root;
}
struct TreeType_C : BasicTree
{
Advanced_C* root;
}
I hope to eventually be able to use these in this manner:
TreeType_A* tree_A;
TreeType_B* tree_B;
TreeType_C* tree_C;
TreeType_A* copy_A;
TreeType_B* copy_B;
TreeType_C* copy_C;
copy_A = tree_A->cloneTree();
copy_B = tree_B->cloneTree();
copy_C = tree_C->cloneTree();
tree_A->root->compute(signature 1);
tree_B->root->compute(signature 1);
tree_C->root->compute(signature 2);
I have two concerns: The cloning of the array of Advanced elements will have to also clone the descendants. At the moment I put his into the method itself:
Base* Instance1::clone()
{
Base* temp = new Instance1();
(clone local stuff)
for (int i = 0; i < numberOfA; i++)
temp->A_array[i] = this->A_array[i]->clone();
for (int i = 0; i < numberOfB; i++)
temp->B_array[i] = this->B_array[i]->clone();
for (int i = 0; i < numberOfA; i++)
temp->C_array[i] = this->C_array[i]->clone();
for (int i = 0; i < numberOfD; i++)
temp->D_array[i] = this->D_array[i]->clone();
return temp;
}
If possible I would actually prefer to write a method cloneChildren that takes care of the recursion transparently.
Mostly I want to avoid having to use explicit casting. Different instances of the Advanced classes have different content, and this content seems to get lost if I try to write, e.g.
temp->A_array[i] = ((Advanced_A*)this->A_array[i])->clone();
On the other hand, using a long case statement based on the particular instance seems inefficient. So it seems I need to rely on automagic.
If further simplifications are possible, such as collapsing everything into a single tree type, or a single array of children, that would be great. (I doubt the former will work, because the compute functions need to look different and return different values for each type of root. The latter seems more promising to me.)
What other pitfalls might there be?

Increment value from void pointer

I'm trying to modify some variables [not necessary from the same class/struct] from keyboard's shortcuts, something like that:
A foo struct containing variables:
struct Foo {
int a;
float b;
};
struct Foo2 {
int c;
};
And a main like:
int main() {
Foo f;
Foo2 f2
void* p = &(f.a); //it could be &(f2.c)
if ('A' key activated) {
*p += 1;
}
}
Currently, I'm stucked at this point:
error: invalid operands to binary expression ('void' and 'int')
The only way to make it work is to change:
*p += 1;
By:
*(int*)p += 1;
Which is not a good solution, because I should not know the type pointed by p. Is there a way to do that?
Converting the pointer to void* lost the type information and the compiler will not know how to increment. Why don't you make a pointer to Foo instead?
int main() {
Foo f;
Foo* p = &f;
if ('A' key activated) {
p->a += 1;
}
}
Also keep in mind that incrementing a float is not a good idea!
For the quesion in the comment of this answer:
struct FooBar
{
int *a;
float *b;
};
int main() {
Foo f;
Bar b;
FooBar fb{&f.a, &b.b};
if ('A' key activated) {
*(fb.a) += 1;
}
}
Note that this solution is rather C-style. Look at lethal-guitar's answer for a more C++-style solution.
Edit: At first I didn't realize that you want to have different types per entry. Based on the task of handling keyboard shortcuts, you could use a polymorphic class, and put instances of it into a std::map:
class KeyHandler {
public:
virtual void onKeyStroke() = 0;
};
class MyHandler : public KeyHandler {
public:
MyHandler(int& value) : myValue(value) {}
virtual void onKeyStroke() {
myValue_ += 1;
}
private:
int& myValue_; // Other subclasses could have other data
};
// Now place instances of different Handlers into a std::map
typedef std::shared_ptr<KeyHandler> PKeyHandler;
std::map<char, PKeyHandler> bindings;
bindings['A'] = PKeyHandler(new IncrementIntHandler(&someInt));
bindings['B'] = PKeyHandler(new IncrementFloatHandler(&someFloat));
// The actual input handler then just invokes
// the correct handler for a key stroke.
bindings[keyCode]->onKeyStroke();
That way, you can define a handler class for every action you want to support, and implement the corresponding logic into these classes. You could make the base class' implementation just do nothing to handle non-mapped keys, etc.
Sure, use an int pointer instead:
int * p = &f.a;
if ( /* condition */ ) { ++*p; }

Base-to-derived class typecast

I have a base class:
class RedBlackTreeNode
{
// Interface is the same as the implementation
public:
RedBlackTreeNode* left;
RedBlackTreeNode* right;
RedBlackTreeNode* parent;
Color color;
TreeNodeData* data;
RedBlackTreeNode():
left(0),
right(0),
parent(0),
color(Black),
data(0)
{
}
// This method is to allow dynamic_cast
virtual void foo()
{
}
};
and a derived from it one:
class IndIntRBNode : public RedBlackTreeNode
{
public:
IndIntRBNode* left;
IndIntRBNode* right;
IndIntRBNode* parent;
IndexedInteger* data;
IndIntRBNode():
RedBlackTreeNode(),
left(0),
right(0),
parent(0),
color(Black),
data(0)
{
}
};
root() and rootHolder are defined in RedBlackTree class:
class RedBlackTree
{
public:
RedBlackTreeNode rootHolder;
RedBlackTreeNode* root()
{
return rootHolder.left;
}
...
}
Then I'm trying to typecast:
IndIntRBNode *x, *y, *z;
z = dynamic_cast<IndIntRBNode*>(root());
And "z" just becomes a zero-pointer, which means that typecast failed.
So what's wrong with it, how can I fix it to be able to reference "z" as pointer to the IndIntRBNode?
Added: the initialization of the rootHolder.left was some kind of that:
int n = atoi(line + i);
tree.clear();
int j = 0;
if (n > 100)
{
n = 100; // Maximum 100 nodes
}
while (j < n)
{
IndexedInteger num(j,j + 10);
RedBlackTreeNode* node;
int c = tree.search(&num, tree.root(), &node);
if (c != 0)
{ // if value is not in the tree
IndexedInteger* v = new IndexedInteger(num);
tree.insert(node, v, c);
++j;
}
}
In the other words, it was initialized on the first iteration of "while" by the "insert" method in such way:
void RedBlackTree::insert(
RedBlackTreeNode* parentNode,
TreeNodeData* v,
// If it's negative, then add as the left son, else as the right
int compare
)
{
assert(parentNode != 0 && compare != 0);
RedBlackTreeNode* x = new RedBlackTreeNode;
x->data = v;
x->parent = parentNode;
// If it's root
if (parentNode == &rootHolder)
{
// Then it must be black
x->color = Black;
}
else
{
// Leaf must be red
x->color = Red;
}
if (compare < 0)
{
// Insert the node as the left son
assert(parentNode->left == NULL);
parentNode->left = x;
}
else
{
// Insert the node as the right son
assert(parentNode != &rootHolder && parentNode->right == NULL);
parentNode->right = x;
}
++numNodes;
if (x != root())
{
rebalanceAfterInsert(x);
}
}
It actually was the problem: "insert" created the RedBlackTreeNode dinamically, so it couldn't be IndIntRBNode.
I really have initialized it wrong, but then how can I derive the base class and not write the whole implementation of it from a scratch just to change the types?
Do I really have to override all the "type-relative" methods in the derived class? It seems to be very stupid, I think there should be the other way - something with class deriving and typecasting, isn't it?
Are you sure that RedBlackTree::rootHolder.left has been initialized?
I think you somewhere initialized IndIntRBNode::left, but when you are accessing RedBlackTree::rootHolder.left you are accessing RedBlackTreeNode::left, which is not the same field.
Wait .. you have a derived class with a type of the same name as the base class. How does that even compile?
how is rootHolder.left initialised? Because if a dynamic_cast fails then it is not of type IndIntRBNode.
Basically you haven't provided enough code to see hy what you are doing is wrong, but you ARE doing something wrong.
If I'm reading your code correctly, you are not setting rootHolder.left to a IndIntRBNode pointer at all, but a vanilla RedBlackTreeNode.
Also, you don't need to make up a useless virtual function for polymorphism; just declare the destructor to be virtual and provide an empty implementation. Your use of polymorphism also isn't that great, as the IndIntRBNode members will hide the RedBlackTreeNode members, so they may well point to different things depending on whether you access them through an IndIntRBNode pointer/reference or a RedBlackTreeNode pointer/reference.
Regardless of whatever other flaws your example code may or may not have, it is written in a way that seems to misunderstand how inheritance and casting work. I recommend that you pick up a C++ book of your choosing and read up on it.
In particular, you should know that every object is one and only one type. Once an object has been created it never changes type. Casting a pointer does not convert an object from one type to another, nor does it create a new object of a new type. Casting allows you to work with an existing object in terms of the class type you specify, but only if that object is already of that class, or a class that is derived from it.
At the point where you currently have this line:
z = dynamic_cast<IndIntRBNode*>(root());
try this instead:
RedBlackTreeNode* other_z = root();
If other_z is not NULL, then root() is not an IndIntRBNode, and all the dynamic_casting in the world won't turn it into one.