My Git:
https://github.com/trueKrogoth/keng/tree/master/keng/obj_types
// note that TComponent doesn't need to know anything about any of the other components
class TComponent {
public:
// note that this doesn't need to be virtual, anymore, though it can call virtual functions internally
void Update();
//...
};
// here's our update function - note that it takes a vector (a dynamic array) of TComponents
void UpdateAll(std::vector<TComponent>& components) {
for (auto& component : components) {
component.Update();
}
}
If you do things the way I'm suggesting, you avoid:I am sorry, I had to remove my OP until I take a better thought.
The concept had 1 toooooo big flaw to handle. (Good I removed it fast, people would laugh)
Yeah, I know that. I just love recursion .)))
Edit:
And recursion isn't slower afaik, due to tail call optimization, is it?
I am sorry, I had to remove my OP until I take a better thought.
The concept had 1 toooooo big flaw to handle. (Good I removed it fast, people would laugh)
Edit:
And recursion isn't slower afaik, due to tail call optimization, is it?
Hey, so after looking at your code, I think the best method would be to have a "world" class hold an array(like std::vector) of objects for updating. Objects should not need to know about all of the objects that are in the world through a linked list. With a "world" class, it also makes it easier to update different components at different times, remove components, and allow components to only worry about their code. This can definitely help reduce bugs later down the road, i.e forgetting to call a Next->Update() function after overriding a component.
Oberon_Command, thank you for wide answer. :]
They say, GCC does optimization even for mutual recursion, converting recursion into loop.
I understand, this is out of C++ style, as I don't even use much containers!
But I like my approach and do not wanna abandon it.
I don't like an idea of something over objects, like a list other than intrusive.
My object functionality lies in the object itself, or to be concrete, in its nature. This is what I am trying to describe with my code.
For example, there is a plane flying. In this case I define plane object as a plane itself and a close air around, that is dynamically changing part of the object. So air resistance influence is a part of plane class.
Easier to understand with a cat that meow meow. I do not define its sound as a part of some Air Vibration class, or some Molecular Forces, or just Physics. But we know that cat couldn't meow without physics. It can try to meow, but it's not exclusively its action, if we do sharp distinction between cat and surrounding physics. Still, the cat class has Meow method, and it's understandable.
Same concept I apply to object update. They update themselves, as momentarily their definition includes all updating factors applied to them. They also delete themselves, though it is not very popular method.
Recursion is much closer to this approach than loop and exists only in source code.
Otherwise I would have to manipulate with iterators rather than pointers. What's the profit?
I would not use std list functionality other than loop. I also add objects in my manner (as it was said, according to 'order index' parameter), and I do not sort anything.
Hey, so after looking at your code, I think the best method would be to have a "world" class hold an array(like std::vector) of objects for updating. Objects should not need to know about all of the objects that are in the world through a linked list. With a "world" class, it also makes it easier to update different components at different times, remove components, and allow components to only worry about their code. This can definitely help reduce bugs later down the road, i.e forgetting to call a Next->Update() function after overriding a component.
Indeed, I should make those full private.
Child components don't need to worry about the list. TObject performs everything itself, and you don't need to put Next->Update() in overriding function. Next->Update() is called by loopUpdate() that is not virtual, but explicitly Object's own and performs call of this particular object's update and the next one's.
And I still reworked it with std::list!
https://github.com/trueKrogoth/keng/blob/master/keng/main/obj_basic_types.cpp
No more intrusive lists and recursion.
+ Replaced array with vector
+ Removed Object, reworked Component as super-class and Basis now :: Component
Emmm...
component->iterator = component_list.insert(++order_component[i]->iterator--, *component);
Are these pre-post increments common thing when you work with iterators?
Basis is the Component that is designed to build other Components.
All Components created are built on some Basis, and they all have pointers to it. Basis, on the other hand, has pointers to some Components that are last Components of certain 'order index', according to which Components are put to the list. For example, Active Window is put over Inactive Window, but still behind Cursor.
Thus Basis is the beginning element of its own Component list,
meanwhile it is just an ordinary Component in its parent Basis' list (if it's not the Null Basis).
Technically speaking, Basis is present in 2 lists at same time. (Yeah, I am gonna make some mystery from there)
And a few more about Null Basis, that it's the thing from which the World starts updating like this:
NullBasis->update();
This is not really mystical; instead it is so common that it has a name: The Composite Pattern.
Letting the question about using a std::xyz structure aside, this ...
QUESTION:
How to organize it? (Especially that 'double presence')
… and this ...
But the problems come as
the last Component must not touch its Basis upon destroying.
How to get it not over-complicating anything?
… is simple to answer: Do not use recursion. The functionality of deleting neighbors is misplaced when placed within the child nodes. Instead let the parent node delete the first child ode as long as child nodes are available.
In other words: The parent node is responsible for its child nodes!
My object functionality lies in the object itself, or to be concrete, in its nature. This is what I am trying to describe with my code.
For example, there is a plane flying. In this case I define plane object as a plane itself and a close air around, that is dynamically changing part of the object. So air resistance influence is a part of plane class.
Easier to understand with a cat that meow meow. I do not define its sound as a part of some Air Vibration class, or some Molecular Forces, or just Physics. But we know that cat couldn't meow without physics. It can try to meow, but it's not exclusively its action, if we do sharp distinction between cat and surrounding physics. Still, the cat class has Meow method, and it's understandable.
Otherwise I would have to manipulate with iterators rather than pointers. What's the profit?
// what you have now
for (std::list<TComponent>::iterator i = component_list.begin(); i != component_list.end(); i++)
i->update();
// what you could have - note that we don't need an iterator, so the code is easier to read
for (TComponent& component : component_list)
component.update();
Finally, what is the __dummy argument to all the constructors for? It doesn't look like it does anything to me.Are these pre-post increments common thing when you work with iterators?