List design (Object oriented) suggestion needed - c++

I'm trying to implement a generic class for lists for an embedded device using C++. Such a class will provide methods to update the list, sort the list, filter the list based on some user specified criteria, group the list based on some user specified criteria etc. But there are quite a few varieties of lists I want this generic class to support and each of these varieties can have different display aspects. Example: One variety of list can have strings and floating point numbers in each of its elements. Other variety could have a bitmap, string and special character in each of it's elements. etc.
I wrote down a class with the methods of interest (sort, group, etc). This class has an object of another class (say DisplayAspect) as its member. But the number of member variables and the type of each member variable of class DisplayAspect is unknown. What would be a better way to implement this?

Why not use the std::list, C++ provides that and it provides all the functionality you mentioned(It is templated class, So it supports all data types you can think of).
Also, there is no point reinventing the wheel as the code you write will almost will never be as efficient as std::list.
In case you still want to reinvent this wheel, You should write a template list class.

First, you should probably use std::list as your list, as others have stated. It seems to me that you are having problems more with what to put in the list, however, so I'm focusing on that part of the question.
Since you want to also store multiple bits of information in each element of the list, you will need to create multiple classes, one to store each combination. You don't describe why you are storing mutiple bits of information, but you'd want to use a logical name for each class. So if, for example, you were storing a name and a price (string and a double), you could give the class some name like Product.
You mention creating a class called DisplayAspect.
If this is because you want to have one piece of code print all of these lists, then you should use inheritance and polymorphism to accomplish this goal. One way to accomplish that is to make your DisplayAspect class an abstract class with the needed functions (printItem() for example) pure virtual and have each of the classes you created for the combinations of data be subclasses of this DisplayAspect class.
If, on the other hand, you created the DisplayAspect class so that you could reuse your list code, you should look into template classes. std::list is an example of a template class and it will hold any type you'd like to put into it and in that case, you could drop your DisplayAspect class.

Others (e.g., #Als) have already given the obvious, direct, answer to the question you asked. If you really want a linked list, they're undoubtedly correct: std::list is the obvious first choice.
I, however, am going to suggest that you probably don't want a linked list at all. A linked list is only rarely a useful data structure. Given what you've said you want (sorting, grouping), and especially your target (embedded system, so you probably don't have a lot of memory to waste) a linked list probably isn't a very good choice for what you're trying to do. At least right off, it sounds like something closer to an array probably makes a lot more sense.
If you end up (mistakenly) deciding that a linked list really is the right choice, there's a fair chance you only need a singly linked list though. For that, you might want to look at Boost Slist. While it's a little extra work to use (it's intrusive), this will generally have lower overhead, so it's at least not quite a poor of a choice as many generic linked lists.

Related

Text Adventure Game - How to Tell One Item Type from Another and How to Structure the Item Classes/Subclasses?

I'm a beginner programmer (who has a bunch of design-related scripting experience for video games but very little programming experience - so just basic stuff like loops, flow control, etc. - although I do have a C++ fundamentals and C++ data structures and algorithm's course under my belt). I'm working on a text-adventure personal project (I actually already wrote it in Python ages ago before I learned how classes work - everything is a dictionary - so it's shameful). I'm "remaking" it in C++ with classes to get out of the rut of having only done homework assignments.
I've written my player and room classes (which were simple since I only need one class for each). I'm onto item classes (an item being anything in a room, such as a torch, a fire, a sign, a container, etc.). I'm unsure how to approach the item base class and derived classes. Here are the problems I'm having.
How do I tell whether an item is of a certain type in a non-shit way (there's a good chance I'm overthinking this)?
For example, I set up my print room info function so that in addition to whatever else it might do, it prints the name of every object in its inventory (i.e. inside of it) and I want it to print something special for a container object (the contents of its inventory for example).
The first part's easy because every item has a name since the name attribute is part of the base item class. The container has an inventory though, which is an attribute unique to the container subclass.
It's my understanding that it's bad form to execute conditional logic based on the object's class type (because one's classes should be polymorphic) and I'm assuming (perhaps incorrectly) that it'd be weird and wrong to put a getHasInventory accessor virtual function in the item base class (my assumption here is based on thinking it'd be crazy to put virtual functions for every derived class in the base class - I have about a dozen derived classes - a couple of which are derived classes of derived classes).
If that's all correct, what's an acceptable way to do this? One obvious thing is to add an itemType attribute to the base and then do conditional logic but this strikes me as wrong since it seems to just be a re-skinning of the checking class type solution. I'm unsure whether the above-mentioned assumptions are correct and what a good solution might be.
How should I structure my base class/classes and my derived classes?
I originally wrote them such that the item class was the base class and most other classes used single inheritance (except for a couple which had multi-level).
This seemed to present some awkwardness and repeating myself though. For example, I want a sign and a letter. A sign is a Readable Item > Untakeable Item > Item. A letter is a Readable Item > Takeable Item > Item. Because they all use single inheritance I need two different Readable Items, one that's takeable and one that's not (I know I could just make takeable and untakeable into attributes of the base in this instance and I did but this works as an example because I still have similar issues with other classes).
That seems icky to me so I took another stab at it and implemented them all using multiple inheritance & virtual inheritance. In my case that seems more flexible because I can compose classes of multiple classes and create a kind of component system for my classes.
Is one of these ways better than the other? Is there some third way that's better?
One possible way to solve your problem is polymorphism. By using polymorphism you can (for example) have a single describe function which when invoked leads the item to describe itself to the player. You can do the same for use, and other common verbs.
Another way is to implement a more advanced input parser, which can recognize objects and pass on the verbs to some (polymorphic) function of the items for themselves to handle. For example each item could have a function returning a list of available verbs, together with a function returning a list of "names" for the items:
struct item
{
// Return a list of verbs this item reacts to
virtual std::vector<std::string> get_verbs() = 0;
// Return a list of name aliases for this item
virtual std::vector<std::string> get_names() = 0;
// Describe this items to the player
virtual void describe(player*) = 0;
// Perform a specific verb, input is the full input line
virtual void perform_verb(std::string verb, std::string input) = 0;
};
class base_torch : public item
{
public:
std::vector<std::string> get_verbs() override
{
return { "light", "extinguish" };
}
// Return true if the torch is lit, false otherwise
bool is_lit();
void perform_verb(std::string verb, std::string) override
{
if (verb == "light")
{
// TODO: Make the torch "lit"
}
else
{
// TODO: Make the torch "extinguished"
}
}
};
class long_brown_torch : public base_torch
{
std::vector<std::string> get_names() override
{
return { "long brown torch", "long torch", "brown torch", "torch" };
}
void describe(player* p) override
{
p->write("This is a long brown torch.");
if (is_lit())
p->write("The torch is burning.");
}
};
Then if the player input e.g. light brown torch the parser looks through all available items (the ones in the players inventory followed by the items in the room), get each items name-list (call the items get_names() function) and compare it to the brown torch. If a match is found the parser calls the items perform_verb function passing the appropriate arguments (item->perform_verb("light", "light brown torch")).
You can even modify the parser (and the items) to handle adjectives separately, or even articles like the, or save the last used item so it can be referenced by using it.
Constructing the different rooms and items is tedious but still trivial once a good design has been made (and you really should spend some time creating requirement, analysis of the requirements, and creating a design). The really hard part is writing a decent parser.
Note that this is only two possible ways to handle items and verbs in such a game. There are many other ways, to many to list them all.
You are asking some excellent questions reg. how to design, structure and implement the program, as well as how to model the problem domain.
OOP, 'methods' and approaches
The questions you ask indicate that you have learned about OOP (object-oriented programming). In a lot of introductory material on OOP, it is common to encourage modelling the problem domain directly through objects and subtyping and implementing functionality by adding methods to them. A classical example is modelling animals, with for instance an Animal type and two sub-types, Duck and Cat, and implementing functionality, for instance walk, quack and mew.
Modelling the problem domain directly with objects and subtyping can make sense, but it can also very much be overkill and bothersome compared to simply having a single or a few types with different fields describing what it is. In your case, I do believe a more complex modelling like you have with objects and subtypes or alternative approaches can make sense, since among other aspects you have functionality that varies depending on the type as well as somewhat complex data (like a container with an inventory). But it is something to keep in mind - there are different trade-offs, and sometimes, having a single type with multiple different fields for modelling the domain can make more sense overall.
Implementing the desired functionality through methods on a base class and subtypes likewise have different trade-offs, and it is not always a good approach for the given case. For one of your questions, you could do something like adding a print method or similar to the base type and each subtype, but this is not always that nice in practice (a simple example is that of a calculator application where simplifying the arithmetic expression the user enters (like (3*x)*4/2) might be bothersome to implement if one uses the approach of adding methods to the base class).
Alternative approach - Tagged unions/sum types
There is a very nice fundamental abstraction known as "tagged union" (it is also known by the names "disjoint union" and "sum type"). The main idea about the tagged union is that you have a union of several different sets of instances, where which set the given instance belongs to matters. They are a superset of the feature in C++ known as enum. Regrettably, C++ does not currently support tagged unions, though there are research into it (for instance https://www.stroustrup.com/OpenPatternMatching.pdf , though this may be somewhat beyond you if you are a beginner programmer). As far as I can see, this fits very well with the example you have given here. An example in Scala would be (many other languages support tagged unions as well, such as Rust, Kotlin, Typescript, the ML-languages, Haskell, etc.):
sealed trait Item {
val name: String
}
case class Book(val name: String) extends Item
case object Fire extends Item {
val name = "Fire"
}
case class Container(val name: String, val inventory: List[Item]) extends Item
This describes your different kinds of items very well as far as I can see. Do note that Scala is a bit special in this regard, since it implements tagged unions through subtyping.
If you then wanted to implement some print functionality, you could then use "pattern matching" to match which item you have and do functionality specific to that item. In languages that support pattern matching, this is convenient and non-fragile, since the pattern matching checks that you have covered each possible case (similar to switch in C++ over enums checking that you have covered each possible case). For instance in Scala:
def getDescription(item: Item): String = {
item match {
case Book(_) | Fire => item.name
case Container(name, inventory) =>
name + " contains: (" +
inventory
.map(getDescription(_))
.mkString(", ") +
")"
}
}
val description = getDescription(
Container("Bag", List(Book("On Spelunking"), Fire))
)
println(description)
You can copy-paste the two snippets in here and try to run them: https://scalafiddle.io/ .
This kind of modelling works very well with what one might call "data types", where you have no or very little functionality in the classes themselves, and where the fields inside the classes basically are part of their interface ("interface" in the sense that you would like to change the implementations that uses the types if you ever add to, remove or change the fields of the types).
Conversely, I find a more conventional subtyping modelling and approach more convenient when the implementation inside of a class is not part of its interface, for instance if I have a base type that describes a collision system interface, and each of its subtypes have different performance characteristics, handy for different situations. Hiding and protecting the implementation since it is not part of the interface makes a lot of sense and fits very well with what one might call "mini-modules".
In C++ (and C), sometimes people do use tagged unions despite the lack of language support, in various ways. One way that I have seen being used in C is to make a C union (though do be careful reg. aspects such as memory and semantics) where an enum tag was used to differentiate between the different cases. This is error-prone, since you might easily end up accessing a field in one enum case that is not valid for that enum case.
You could also model your command input as a tagged union. That said, parsing can be somewhat challenging, and parsing libraries may be a bit involved if you are a beginner programmer; keeping the parsing somewhat simple might be a good idea.
Side-notes
C++ is a special languages - I do not quite like it for cases where I do not care much about resource usage or runtime performance and the like for multiple different reasons, since it can be annoying and not that flexible to develop in. And it can be challenging to develop in, because you must always take great care to avoid undefined behaviour. That said, if resource usage or runtime performance do matter, C++ can, depending on case, be a very good option. There are also a number of very useful and important insights in the C++ language and its community, such as RAII, ownership and lifetimes. My recommendation is that learning C++ is a good idea, but that you should also learn other languages, maybe for instance a statically-typed functional programming language. FP (functional programming) and languages supporting FP, has a number of advantages and drawbacks, but some of their advantages are very, very nice, especially reg. immutability as well as side-effects.
Of these languages, Rust may be the closest to C++ in certain regards, though I don't have experience with Rust and cannot therefore vouch for either the language or its community.
As a side-note, you may be interested in this Wikipedia-page: https://en.wikipedia.org/wiki/Expression_problem .

c++: search vector of base class pointers

I'm trying to create something like an analogue for Python's list. There are some objects derived from class Object. There is also class List, which is just a overlay for std::vector<Object*>. All classes have clone function (as well as some other functions). Now I'm trying to provide a possibility to find an index for the given element (like Python's list.index). It would be also great to provide a possibility to sort in future, i.e. to compare objects inside List class. How can I realise it without having to overload operator==? I've heard about hashing algorithms. Is it the thing that I'm looking for? If yes, could you advice a library or (better) how can I implement it using raw C++?
Thanks in advance!

Single-use class

In a project I am working on, we have several "disposable" classes. What I mean by disposable is that they are a class where you call some methods to set up the info, and you call what equates to a doit function. You doit once and throw them away. If you want to doit again, you have to create another instance of the class. The reason they're not reduced to single functions is that they must store state for after they doit for the user to get information about what happened and it seems to be not very clean to return a bunch of things through reference parameters. It's not a singleton but not a normal class either.
Is this a bad way to do things? Is there a better design pattern for this sort of thing? Or should I just give in and make the user pass in a boatload of reference parameters to return a bunch of things through?
What you describe is not a class (state + methods to alter it), but an algorithm (map input data to output data):
result_t do_it(parameters_t);
Why do you think you need a class for that?
Sounds like your class is basically a parameter block in a thin disguise.
There's nothing wrong with that IMO, and it's certainly better than a function with so many parameters it's hard to keep track of which is which.
It can also be a good idea when there's a lot of input parameters - several setup methods can set up a few of those at a time, so that the names of the setup functions give more clue as to which parameter is which. Also, you can cover different ways of setting up the same parameters using alternative setter functions - either overloads or with different names. You might even use a simple state-machine or flag system to ensure the correct setups are done.
However, it should really be possible to recycle your instances without having to delete and recreate. A "reset" method, perhaps.
As Konrad suggests, this is perhaps misleading. The reset method shouldn't be seen as a replacement for the constructor - it's the constructors job to put the object into a self-consistent initialised state, not the reset methods. Object should be self-consistent at all times.
Unless there's a reason for making cumulative-running-total-style do-it calls, the caller should never have to call reset explicitly - it should be built into the do-it call as the first step.
I still decided, on reflection, to strike that out - not so much because of Jalfs comment, but because of the hairs I had to split to argue the point ;-) - Basically, I figure I almost always have a reset method for this style of class, partly because my "tools" usually have multiple related kinds of "do it" (e.g. "insert", "search" and "delete" for a tree tool), and shared mode. The mode is just some input fields, in parameter block terms, but that doesn't mean I want to keep re-initializing. But just because this pattern happens a lot for me, doesn't mean it should be a point of principle.
I even have a name for these things (not limited to the single-operation case) - "tool" classes. A "tree_searching_tool" will be a class that searches (but doesn't contain) a tree, for example, though in practice I'd have a "tree_tool" that implements several tree-related operations.
Basically, even parameter blocks in C should ideally provide a kind of abstraction that gives it some order beyond being just a bunch of parameters. "Tool" is a (vague) abstraction. Classes are a major means of handling abstraction in C++.
I have used a similar design and wondered about this too. A fictive simplified example could look like this:
FileDownloader downloader(url);
downloader.download();
downloader.result(); // get the path to the downloaded file
To make it reusable I store it in a boost::scoped_ptr:
boost::scoped_ptr<FileDownloader> downloader;
// Download first file
downloader.reset(new FileDownloader(url1));
downloader->download();
// Download second file
downloader.reset(new FileDownloader(url2));
downloader->download();
To answer your question: I think it's ok. I have not found any problems with this design.
As far as I can tell you are describing a class that represents an algorithm. You configure the algorithm, then you run the algorithm and then you get the result of the algorithm. I see nothing wrong with putting those steps together in a class if the alternative is a function that takes 7 configuration parameters and 5 output references.
This structuring of code also has the advantage that you can split your algorithm into several steps and put them in separate private member functions. You can do that without a class too, but that can lead to the sub-functions having many parameters if the algorithm has a lot of state. In a class you can conveniently represent that state through member variables.
One thing you might want to look out for is that structuring your code like this could easily tempt you to use inheritance to share code among similar algorithms. If algorithm A defines a private helper function that algorithm B needs, it's easy to make that member function protected and then access that helper function by having class B derive from class A. It could also feel natural to define a third class C that contains the common code and then have A and B derive from C. As a rule of thumb, inheritance used only to share code in non-virtual methods is not the best way - it's inflexible, you end up having to take on the data members of the super class and you break the encapsulation of the super class. As a rule of thumb for that situation, prefer factoring the common code out of both classes without using inheritance. You can factor that code into a non-member function or you might factor it into a utility class that you then use without deriving from it.
YMMV - what is best depends on the specific situation. Factoring code into a common super class is the basis for the template method pattern, so when using virtual methods inheritance might be what you want.
Nothing especially wrong with the concept. You should try to set it up so that the objects in question can generally be auto-allocated vs having to be newed -- significant performance savings in most cases. And you probably shouldn't use the technique for highly performance-sensitive code unless you know your compiler generates it efficiently.
I disagree that the class you're describing "is not a normal class". It has state and it has behavior. You've pointed out that it has a relatively short lifespan, but that doesn't make it any less of a class.
Short-lived classes vs. functions with out-params:
I agree that your short-lived classes are probably a little more intuitive and easier to maintain than a function which takes many out-params (or 1 complex out-param). However, I suspect a function will perform slightly better, because you won't be taking the time to instantiate a new short-lived object. If it's a simple class, that performance difference is probably negligible. However, if you're talking about an extremely performance-intensive environment, it might be a consideration for you.
Short-lived classes: creating new vs. re-using instances:
There's plenty of examples where instances of classes are re-used: thread-pools, DB-connection pools (probably darn near any software construct ending in 'pool' :). In my experience, they seem to be used when instantiating the object is an expensive operation. Your small, short-lived classes don't sound like they're expensive to instantiate, so I wouldn't bother trying to re-use them. You may find that whatever pooling mechanism you implement, actually costs MORE (performance-wise) than simply instantiating new objects whenever needed.

Most efficient way to add data to an instance

I have a class, let's say Person, which is managed by another class/module, let's say PersonPool.
I have another module in my application, let's say module M, that wants to associate information with a person, in the most efficient way. I considered the following alternatives:
Add a data member to Person, which is accessed by the other part of the application. Advantage is that it is probably the fastest way. Disadvantage is that this is quite invasive. Person doesn't need to know anything about this extra data, and if I want to shield this data member from other modules, I need to make it private and make module M a friend, which I don't like.
Add a 'generic' property bag to Person, in which other modules can add additional properties. Advantage is that it's not invasive (besides having the property bag), and it's easy to add 'properties' by other modules as well. Disadvantage is that it is much slower than simply getting the value directly from Person.
Use a map/hashmap in module M, which maps the Person (pointer, id) to the value we want to store. This looks like the best solution in terms of separation of data, but again is much slower.
Give each person a unique number and make sure that no two persons ever get the same number during history (I don't even want to have these persons reuse a number, because then data of an old person may be mixed up with the data of a new person). Then the external module can simply use a vector to map the person's unique number to the specific data. Advantage is that we don't invade the Person class with data it doesn't need to know of (except his unique nubmer), and that we have a quick way of getting the data specifically for module M from the vector. Disadvantage is that the vector may become really big if lots of persons are deleted and created (because we don't want to reuse the unique number).
In the last alternative, the problem could be solved by using a sparse vector, but I don't know if there are very efficient implementations of a sparse vector (faster than a map/hashmap).
Are there other ways of getting this done?
Or is there an efficient sparse vector that might solve the memory problem of the last alternative?
I would time the solution with map/hashmap and go with it if it performs good enough. Otherwise you have no choice but add those properties to the class as this is the most efficient way.
Alternatively, you can create a subclass of Person, basically forward all the interface methods to the original class but add all the properties you want and just change original Person to your own modified one during some of the calls to M.
This way module M will see the subclass and all the properties it needs but all other modules would think of it as just an instance of Person class and will not be able to see your custom properties.
The first and third are reasonably common techniques. The second is how dynamic programming languages such as Python and Javascript implement member data for objects, so do not dismiss it out of hand as impossibly slow. The fourth is in the same ballpark as how relational databases work. It is possible, but difficult, to make relational databases run the like the clappers.
In short, you've described 4 widely used techniques. The only way to rule any of them out is with details specific to your problem (required performance, number of Persons, number of properties, number of modules in your code that will want to do this, etc), and corresponding measurements.
Another possibility is for module M to define a class which inherits from Person, and adds extra data members. The principle here is that M's idea of a person differs from Person's idea of a person, so describe M's idea as a class. Of course this only works if all other modules operating on the same Person objects are doing so via polymorphism, and furthermore if M can be made responsible for creating the objects (perhaps via dependency injection of a factory). That's quite a big "if". An even bigger one, if nothing other than M needs to do anything life-cycle-ish with the objects, then you may be able to use composition or private inheritance in preference to public inheritance. But none of it is any use if module N is going to create a collection of Persons, and then module M wants to attach extra data to them.

Structure for hierarchal Component storage

I've been batting this problem around in my head for a few days now and haven't come to any satisfactory conclusions so I figured I would ask the SO crew for their opinion. For a game that I'm working on I'm using a Component Object Model as described here and here. It's actually going fairly well but my current storage solution is turning out to be limiting (I can only request components by their class name or an arbitrary "family" name). What I would like is the ability to request a given type and iterate through all components of that type or any type derived from it.
In considering this I've first implemented a simple RTTI scheme that stores the base class type through the derived type in that order. This means that the RTTI for, say, a sprite would be: component::renderable::sprite. This allows me to compare types easily to see if type A is derived from type B simply by comparing the all elements of B: i.e. component::renderable::sprite is derived from component::renderable but not component::timer. Simple, effective, and already implemented.
What I want now is a way to store the components in a way that represents that hierarchy. The first thing that comes to mind is a tree using the types as nodes, like so:
component
/ \
timer renderable
/ / \
shotTimer sprite particle
At each node I would store a list of all components of that type. That way requesting the "component::renderable" node will give me access to all renderable components regardless of derived type. The rub is that I want to be able to access those components with an iterator, so that I could do something like this:
for_each(renderable.begin(), renderable.end(), renderFunc);
and have that iterate over the entire tree from renderable down. I have this pretty much working using a really ugly map/vector/tree node structure and an custom forward iterator that tracks a node stack of where I've been. All the while implementing, though, I felt that there must be a better, clearer way... I just can't think of one :(
So the question is: Am I over-complicating this needlessly? Is there some obvious simplification I'm missing, or pre-existing structure I should be using? Or is this just inheritly a complex problem and I'm probably doing just fine already?
Thanks for any input you have!
You should think about how often you need to do the following:
traverse the tree
add/remove elements from the tree
how many objects do you need to keep track of
Which is more frequent will help determine the optimum solution
Perhaps instead of make a complex tree, just have a list of all types and add a pointer to the object for each type it is derived from. Something like this:
map<string,set<componenet *>> myTypeList
Then for an object that is of type component::renderable::sprite
myTypeList["component"].insert(&object);
myTypeList["renderable"].insert(&object);
myTypeList["sprite"].insert(&object);
By registering each obejct in multiple lists, it then becomes easy to do something to all object of a given type and subtypes
for_each(myTypeList["renderable"].begin(),myTypeList["renderable"].end(),renderFunc);
Note that std::set and my std::map construct may not be the optimum choice, depending on how you will use it.
Or perhaps a hybrid approach storing only the class heirarchy in the tree
map<string, set<string> > myTypeList;
map<string, set<component *> myObjectList;
myTypeList["component"].insert("component");
myTypeList["component"].insert("renderable");
myTypeList["component"].insert("sprite");
myTypeList["renderable"].insert("renderable");
myTypeList["renderable"].insert("sprite");
myTypeList["sprite"].insert("sprite");
// this isn't quite right, but you get the idea
struct doForList {
UnaryFunction f;
doForList(UnaryFunction f): func(f) {};
operator ()(string typename) {
for_each(myTypeList[typename].begin();myTypeList[typename].end(), func);
}
}
for_each(myTypeList["renderable"].begin(),myTypeList["renderable"].end(), doForList(myFunc))
The answer depends on the order you need them in. You pretty much have a choice of preorder, postorder, and inorder. Thus have obvious analogues in breadth first and depth first search, and in general you'll have trouble beating them.
Now, if you constraint the problem a litle, there are a number of old fashioned algorithms for storing trees of arbitrary data as arrays. We used them a lot in the FORTRAN days. One of them had the key trick being to store the children of A, say A2 and A3, at index(A)*2,index(A)*2+1. The problem is that if your tree is sparse you waste space, and the size of your tree is limited by the array size. But, if I remember this right, you get the elements in breadth-first order by simple DO loop.
Have a look at Knuth Volume 3, there is a TON of that stuff in there.
If you want to see code for an existing implementation, the Game Programming Gems 5 article referenced in the Cowboy Programming page comes with a somewhat stripped down version of the code we used for our component system (I did a fair chunk of the design and implementation of the system described in that article).
I'd need to go back and recheck the code, which I can't do right now, we didn't represent things in a hierarchy in the way you show. Although components lived in a class hierarchy in code, the runtime representation was a flat list. Components just declared a list of interfaces that they implemented. The user could query for interfaces or concrete types.
So, in your example, Sprite and Particle would declare that they implemented the RENDERABLE interface, and if we wanted to do something to all renderables, we'd just loop through the list of active components and check each one. Not terribly efficient on the face of it, but it was fine in practice. The main reason it wasn't an issue was that it actually turns out to not be a very common operation. Things like renderables, for example, added themselves to the render scene at creation, so the global scene manager maintained its own list of renderable objects and never needed to query the component system for them. Similarly with phyics and collision components and that sort of thing.