How to design OO graph node classes with improved usability & readability? - c++

This is a basic OO design question. I'm writing classes in C++ to represent items in a flow chart according to an input C file that have been parsed.
Simply we have 2 types of items (classes) : FlowChartActionItem and FlowChartConditionItem.
These represent Actions and Decision/Condition elements of a flowchart respectively. And they also represent Statements and If-conditions respectively, that existed in the input C file. Both classes inherit FlowChartItem.
Each sub-classes has a number of pointers to the items that comes after them; yes, we have a graph, with nodes(items) and links(pointers). But the FlowChartActionItem has only one outward pointer while the FlowChartConditionItem has 3 outward pointers (for the then-statements branch, the else-statements branch and a pointer to whatever comes after the both branches of the if-condition.
My problem is writing a neat setter for the outward pointers (nextItems). Take a look at the classes :
class FlowChartItem
{
public:
//I **need** this setter to stay in the parent class FlowChartItem
virtual void SetNextItem(FlowChartItem* nextItem, char index) = NULL;
};
-
class FlowChartActionItem:public FlowChartItem
{
public:
FlowChartItem* nextItem; //Only 1 next item
public:
void SetNextItem(FlowChartItem* nextItem, char index);
};
-
class FlowChartConditionItem: public FlowChartItem
{
public:
FlowChartItem* nextItem;
FlowChartItem* trueBranchItem;
FlowChartItem* falseBranchItem; //we have 3 next items here
public:
void SetNextItem(FlowChartItem* nextItem, char index);
};
I needed a generic setter that doesn't depend on the number of pointers the sub-class is having.
As you see I've used char index to tell the setter which pointer is to be set. But I don't like this and I need to make things neater. Because code won't be readable e.g :
item1.setNextItem(item2,1);
we don't remember what the 1 means? the then-branch ? the else ? ??
The obvious answer is to define an enum in FlowCharItem, but then we'll have one of two problems :
1- Enum values will be defined Now and will thus be tailored for the current sub-classes FlowChartActioItem and FlowChartConditionItem, so calls to SetNextItem on future sub-classes will have very bad readability. And even worse, they cannot have more than 3 outward pointers!
2- Solve the 1st problem by making developers of the future sub-classes edit the header file of FlowChartItem and add whatever values in the enum ! of course not acceptable!
What solution do I have in order to keep
-good readability
-neat extensibility of my classes ??

This is a form of a common architecture dilemma. Different child classes have a shared behavior that differs slightly and you need to somehow extract the common essence to the base class in a way that makes sense. A trap that you will typically regret is to let the child class functionality bleed into the parent class. For instance I would not recommend a set of potential enum names for types of output connections defined in FlowChartItem. Those names would only make sense in the individual child nodes that use them. It would be similarly bad to complicate each of your sub classes to accommodate the design of their siblings. Above all things, KIS! Keep. It. Simple.
In this case, it feels like you're overthinking it. Design your parent class around the abstract concept of what it represents and how it will be used by other code, not how it's inheritors will specialize it.
The name SetNextItem could just be changed to make it more clear what both of the parameters do. It's only the "next" item in the sense of your entire chart, not in the context of a single FlowChartItem. A flow chart is a directed graph and each node would typically only know about itself and it's connections. (Also, you're not writing visual basic, so containers index starting from 0! :-) )
virtual void SetOutConnectionByIndex(FlowChartItem* nextItem, char index);
Or if you prefer shorter names, then you could set the "N'th" output item: SetNthOutItem.
Since it not valid to set a child using an out-of-range index, then you probably want to have another pure virtual function in FlowChartItem that returns the maximum number of supported children and make SetChildByIndex return a success/failure code (or if you're one of those people, throw an exception) if the index is out of range.
virtual bool SetChildByIndex(FlowChartItem* item, char index);
Now... having written all that, I start to wonder about the code you have that will call this function. Does it really only know about each node as a FlowChartItem, but still needs to set it's children in a particular order which it doesn't know the significance of? This might be valid if you have other code which is aware of the real item types and the meaning of their child orderings and that code is providing the item pointers and their index numbers to the code that does the setting. Maybe de-serialization code, but this is not the right way to handle serialization. Is FlowChartItem exposed through a strict API and the chart is built up by code that knows of the different types of flow chart items but does not have access to the actual classes? Maybe valid in that case, but I'm speculating now well beyond the details you've provided.
But if this function is only going to be called by code that knows the real item type, has access to the actual class, and knows what the index means, then this probably shouldn't be in the base class at all.
I can, however, imagine lots of types of code that would need to fetch a FlowChartItem's children in order, without knowing the significance of that order. Code to draw your flow chart, code to execute your flow-chart, whatever. If you cut your question down for brevity and are also thinking about similar getter method, then the above advice would apply (though you could also consider an iterator pattern).

I'm sidestepping your dubious need for a "generic" SetNextItem in the base class, and will propose a way you can implement your idea.
You could store FlowChartItem* items in a std::map<std::string, FlowChartItems*> (what I call an adjacency map), and set the items by name. This way, subclasses can have as many adjacencies as they want and there's no need to maintain a central enum of adjacency types.
class FlowChartItem
{
public:
virtual void SetAdjacency(FlowChartItem* item, const std::string &type)
{
// Enforce the use of a valid adjacency name
assert(NameSet().count(type) != 0);
adjacencyMap_[name] = nextItem
}
protected:
// Subclasses must override this and return a set of valid adjacency names
const std::set<std::string>& NameSet() = 0;
std::map<std::string, FlowChartItem*> adjacencyMap_;
};
class FlowChartActionItem : public FlowChartItem
{
public:
// Convenience member function for when we're dealing directly
// with a FlowChartActionItem.
void SetNextItem(FlowChartItem* item) {SetAdjacency(item, "next");}
protected:
const std::set<std::string>& NameSet()
{
// Initialize static nameSet_ if emtpy
return nameSet_;
}
private:
// One set for the whole class (static).
const static std::set<std::string> nameSet_;
static std::set<std::string> MakeNameSet()
{
std::set<std::string> names;
names.insert("next");
return names;
}
}
// Initialize static member
const std::set<std::string> FlowChartActionItem::nameSet_ =
FlowChartActionItem::MakeNameSet();
Usage:
item1.SetAdjacency(&item2, "next");

I needed a generic setter that doesn't depend on the number of
pointers the sub-class is having.
The only way to have a mutable structure like this is to allow the client to access a data structure, say, std::vector<FlowChartItem*> or std::unordered_map<unsigned int, FlowChartItem*> or whatever. They can read it and set the values.
Fundamentally, as long as you're trying to dynamically set static items, you're going to have a mess. You're trying to implement your own, highly primitive, reflection system.
You need to have dynamic items if you want them to be dynamically set without a language-built-in reflection system or endlessly wasting your life jerking around trying to make it work.
As a bonus, if you have something like that, the use case for your derived classes just got a lot lower, and you could maybe even get rid of them. WinRARâ„¢.

Related

Should I make a class polymorphic if only one of its methods should behave differently depending on the object's data type?

I have a class Group containing a vector of objects of another class Entry. Inside the Group I need to frequently access the elements of this vector(either consequently and in random order). The Entry class can represent a data of two different types with the same properties(size, content, creation time etc.). So all of the members and methods of the Entry class are the same for both data types, except for one method, that should behave differently depending on the type of the data. It looks like this:
class Entry
{
public:
// ...
void someMethod();
// ...
private:
TYPE type_;
// ...
};
class Group
{
private:
// ...
std::vector<Entry> entries_;
// ...
};
void Entry::someMethod()
{
if (type_ == certainType)
{
// Do some stuff
}
else if (type_ == anotherType)
{
// Do some different stuff
}
}
Given the abilities of C++ regarding OOP, this approach seems unnatural to me. I am thinking about creation of two distinct classes inherited from the Entry class and overriding only this someMethod() in those classes:
class Entry
{
// ...
virtual void someMethod() = 0;
// ...
};
class EntryType1 : public Entry
{
// override someMethod() here
};
class EntryType2 : public Entry
{
// override someMethod() here
};
But doing so means reducing the efficiency of cache usage, because now inside the Group class I have to replace the vector of Entry objects placed in a contiguous memory area with the vector of pointers to Entry base class objects scattered all over the memory address space.
The question is - is it worth it to make a class polymorphic just because of one only among many other of its methods is needed to behave differently depending on the data type? Is there any better approach?
is it worth it to make a class polymorphic just because of one only among many other of its method is needed to behave differently depending on the data type?
Runtime polymorphism starts to provide undeniable net value when the class hierarchy is deep, or may grow arbitrarily in future. So, if this code is just used in the private implementation of a small library you're writing, start with what's more efficient if you have real reason to care about efficiency (type_ and if), then it's not much work to change it later anyway. If lots of client code may start to depend your choices here though, making it difficult to change later, and there's some prospect of further versions of someMethod() being needed, it's probably better to start with the virtual dispatch approach.
Is there any better approach?
Again - what's "better" takes shape at scale and depends on how the code is depended upon, updated etc.. Other possible approaches include using a std::variant<EntryType1, EntryType2>, or even a std::any object, function pointers....
If you are absolutely sure that there are only two types of Entry, then using an if inside the function's implementation is, to me, a perfectly valid approach. In this case, I would advise you to use if constexpr to further indicate that this is a compile-time behavioral decision and not a runtime one. (As pointed out by Tony Delroy, if constexpr is not viable).
If, however, you are unsure if you are going to need more Entry types in the future, the if approach would only hurt you in the long run. If you need the scalability, I would advise you to make the Entry class hold a std::function internally for only that specific behavior that needs polymorphism: this way you're only paying for indirection when you actually need the functionality.
You could also make two factory functions make_Entry1 and make_Entry2 that construct an Entry passing it the specific std::function that yields the desired behavior.

C++ Model View Design

I am currently struggling with the design of an application of the visualization and manipulation of sensor data. I have a database that contains several STL-containers with measured data in it.
std::unordered_map<std::string, std::array<uint16_t, 3366>> data1;
std::unordered_map<std::string, QImage> data2;
std::unordered_map<std::string, std::vector<Point3D>> data3;
I also have different Views (mostly Qt-based) and each view should be associated with a model which is specific to one of the data sets. So data1 is supposed to be processed and manipulated in a class called model1 which is then displayed by means of a class view1 and so forth.
But I cant seem to find a suitable design structure to incorporate this idea. the models grant access to their processed data, but that data is contained in different container structures as given above. That makes it unfeasible to use inheritance with a pure virtual function in the base class like
std::map<...,...> getModelData() = 0;
The initial idea of this inheritance was to avoid code duplication but that doesnt seem to be the right solution here. I know that Qt in their "Model-View" concepts makes use of their QVariant class to have maximum flexibility in terms of types being returned. However, I am wondering, what is the best solution with standard C++ here? I read a lot about striving for loose-coupling, code reuseability, Dependendy Inversion and how to favour composition over inheritance but I do have problems putting these theoretical advise into practice and end up with code bloat and repetitive code most of the times. Can you help me?
Maybe you can give more code but so far, I can give a few hints:
-Can you use QMap instead of std::unordered_map ? It is more agile if you need to tangle with a UI
-Maybe make your second argument of the list a common base type like (code not tested, treat as pseudo code)
class BaseDataClass
{
public:
int getType();
QImage* getImageData();
std::array<uint16_t, 3366>>& getArray();
std::vector<Point3D>>& getVector();
private:
int mType;
BaseDataClass(); //hide ctor or make abstract, as you wish
}
You can avoid code duplicating with this. Make three new classes that each inherit from BaseDataClass. You can then make a method that iterates over all BaseDataClass, checks the type (e.g. 1=QImage; 2 = array ; 3 = vector), and exectues the right method according to the type (get QImage from all type 1`s ...). You also can cast the pointer to the right type then. Which makes it even better if your derived classes gain more and more functionality (like sorting or validating data)

C++ Template Classes, Inheritance and Writing Generic Code for Graph Drawing

Background Info
I am writing a graph-drawing program. I have encountered a problem with templates and inheritance, and I do not know how to proceed. I do not know how I should design my code to enable me to do what I am trying to do. (Explanation below.)
Target
I have a template class, which represents "data". It looks something like the following:
template<typename T>
class GraphData
{
std::vector<T> data_x;
std::vector<T> data_y; // x and y should be held in separate vectors
}
This class is part of an inheritance hierarchy involving several classes.
The hierarchy looks something like this... (Sorry this is from my notes, awful diagram.)
Explanation
There is a base class. No real reason to have it right now, but I anticipate using it later.
Base_Legend adds functionality for legend drawing. New members added include a std::string, and Get/Set functions.
Base_Drawable adds a pure abstract = 0 member. void Draw(...). This is to force overloading in all inherited objects which are drawable.
GraphData_Generic adds functionality for adding/removing data points to a set of vectors. These are pure abstract methods, and must be overridden by any data classes which inherit.
GraphData and HistogramData are 2 data types which have implementations of the functions from GraphData_Generic. (No implementation of Draw().)
GraphData_GenericDrawable doesn't do anything. It is to be used as a base class pointer, so that a vector of these objects can be used as data (add/remove data points) and can be draw (using void Draw()). This class also can be used to call the Get()/Set() methods for the std::string to be used in the legend.
Finally, at the bottom are GraphData_Drawable and HistogramData_Drawable which overload the void Draw() function. This code specifies exactly how the data should be drawn, depending on whether we have a Histogram or general set of data points.
Problem
Currently, I am using template types. The type of data for the datapoints / histogram bin values is specified by using a template.
For example, one can have a HistogramData<double, HistogramData_Drawable<double>, HistogramData_Drawable<int>, etc... Similarly, one can have GraphData<double>, GraphData<float>, GraphData_Drawable`, etc...
So hopefully it should be fairly obvious what's going on here without me uploading my ~ 10000 lines of code...
Right, so, in addition I have some class Graph, which contains a std::vector<GraphData_Generic_Drawable*>, hence the use of the base class pointer, as suggested above.
BUT! One has to decide what type of data should be used as the underlying type. I MUST choose either std::vector<GraphData_Generic_Drawable<double>*> or std::vector<GraphData_Generic_Drawable<float>*>.
This isn't useful, for obvious reasons! (I could choose double and force the user to convert all values manually, but that's just an easy way out which creates more work later on.)
A (very) ugly solution would be to have a std::vector<> for each possible type... int long unsigned long long double float unsigned char... etc...
Obviously this is going to be hideous and essentially repeat loads of code..
So, I intend to implement an AddData method which adds data to that vector, and I also currently have the following method:
// In class Graph
void DrawAll()
{
for(std::vector<GraphData_Drawable*>::iterator it = m_data.begin(); it != m_data.end(); ++ it)
(*iterator)->Draw(arguments);
} // Draw function takes arguments including a canvas to draw to, but this isn't directly relevant to the question
Which iterates over the vector and calls Draw for each set of data in there.
How to fix it?
My current thoughts are something along the lines of; I need to implement some sort of interface for an underlying data class, which retrieves values independent of the underlying type. But this is only a very vague initial idea and I'm not really sure how I would go about implementing this, hence the question... I'm not sure this is even what I should be doing...
If this isn't clear ask me a question and I'll update this with more details.

How to Avoid Using Getters/Setters in C++?

I understand the reason why we should avoid using getters/setters, but I don't know how to avoid using them.
For example, I have three classes as follows,
A (private: point_B)
B (private: point_C)
C (private: val_C)
A has a private member point_B which is a pointer that points to B, and B also has a private member point_C which is a pointer that points to C. And C has a private int value val_C.
How can I access val_C in A?
Update:
In this case,
A is a class called state, which has the address point_B.
B is a class called node, which has a pointer call pointer_C.
C is a class called base_file, which has two derived classes called file and directory.
Update 2:
Ty guys for you help. Some of you are really trying to help instead of acting like someone who knows everything. I appreciate it.
Sry I can't post the whole assignment here since its too large even without documents. I'll post professor's answer here if you guys are interested tomorrow.
Update 3:
Please find reference here
The right thing to do is to leave the implementation to specify class.
Update 4:
The answer is to not to access private value in each class, but to implement functions to use them. That explains why making them private at the first place.
Maybe a little clarification is in order -- getters and setters aren't meant to be avoided at all costs; they have their place. The reason people say they should be avoided is because one goal of good object-oriented program design is encapsulation -- that is to say, each class should keep the details of its own implementation as private as possible, so that users of that class don't need to know (or care) about how the class was implemented. This becomes increasingly important as the program gets larger and more complicated, because a human programmer can only keep so many details in his/her head at once, and if the programmer has to remember everything about how class C works while simultaneously writing/debugging class A, that's an additional/unecessary cognitive burden that at some point will cause the programmer's brain to explode.
So, getting back to the main question -- how to avoid getters and setters -- the way to do it is to define your classes' interfaces at a higher level of abstraction than as simple repositories for state variables. (After all, if you wanted a simple collection of state variables, there's no reason to use a C++ class at all, you could simply declare a C-style struct instead)
For example, if your class C was intended to represent, say, a slot machine, a poor interface to class C might include lots of getters and setters, like this:
int getNumCoins() const {return numCoins;}
void setNumCoins(int newCoinCount) {numCounts = newCoinCount;}
void setDisplayedResult(const string & displayStr) {result = displayStr;}
int getDisplayedResult() const {return result;}
... and the poor programmer who was forced to use class C would have to write code like this:
playersWallet--; // take a coin out of the player's wallet
c.setNumCoins(c.getNumCoins()+1); // insert the coin into the machine
string newResult = "10 J A"; // somehow figure out what the machine should display
c.setDisplayedResult(newResult); // and make the machine display it
if (c.getDisplayedResult() == "7 7 7")
{
cout << "YOU ARE WINNER!" << endl;
int numCoinsWon = 5000; // jackpot!
c.setNumCoins(c.getNumCoins()-numCoinsWon); // deduct from machine's balance
playersWallet += numCoinsWon; // add to player's balance
}
[... and so on...]
Note that in the above code, the programmer had to think about all of the internal mechanisms of the slot machine, and write his own code to handle each step of its operation. With good encapsulation, on the other hand, the slot machine's public interface would be much simpler and more opaque, like this:
// returns the number of coins the player won on this round
int pullTheBigLever();
... and the programmer who was using this API might write code like this:
playersWallet += (c.pullTheBigLever() - 1); // -1 for the coin the player put in
Note that there is only one line of code, and that the programmer didn't have to think at all about how the internals of the slot machine worked. This avoids exploding-programmer-brain-syndrome, and just as importantly it means you (or someone else) can go back later and change the private implementation of how the slot machine works without breaking the code that interacts with the slot machine.
So when are getters and setters acceptable? Answer: when there really isn't any higher level of abstraction to be had. If you are writing a class that represents a light switch, then just being able to examine the switch's current position, or specify a new position for it, may be all the functionality you need. But in many (most?) cases you are implementing the functionality of something more complex than that, and the more of that complexity you can hide behind your public interface, the happier users of that class (including you) will be.
Short answers, in OOP, classes should have "properties" as part of their public API. Properties can have have things like getters, setters and change notifications, as appropriate. Wether a getter directly returns a private member variable, that is an implementation detail, and could change as needed. Distinguish the concept of property from the concept of member variable.
When thinking about it like this, the direct answer to your question is, that there's nothing you should try to "avoid", other than having unnecessary readable properties.
Note that often there is no explicit syntax or support for properties in an object oriented language (popular counter-example: C#), so it's easy to think they are same thing as a member variable with a setter and a getter. But the overlap is sort of a coincident, and not something you should care about when using a class. In a way, there is no getter for a member variable, there is only a getter for the property, even if it happens to map 1:1 with a member variable.
How avoid using getters/setters in C++.
To avoid setter/getter, all code that accesses a data attribute of class C, must be part of a class C method.
Alternate wording: bring the code that uses the data attribute inside the class.
update 2016/01/25
Would an example help? I find it trivial to avoid getters and setters (and public data and friends, etc.) I suppose I'm just used to it.
I recently completed yet another implementation of the game-of-life. The whole game is the entertainment value of watching the cells change patterns. Impressively complex behaviour from a small set of rules.
My class Cell_t has ONLY private data, No getters, no setters, and no friends. No other class has access to any cells data.
Here is a snippet of that part of my game illustrating how easy it is to live without getters, setters and friends creating the undesirable coupling and cohesion:
// somewhere in GameOfLife exists
std::vector<Cell_t> m_ptCellVec; // a vector of cell ptrs
GameOfLife::exec(...)
{
// ... preliminary stuff
do {
// ... some preliminary stuff
// NOTE 1
for ( auto it : m_ptCellVec ) it->countNeighbor();
// NOTE 2
for ( auto it : m_ptCellVec ) { it->updateDisplay();}
// .... more stuff
if(timeElapsed > timeLimit) break;
if(m_generation > genLimit) break;
}while(1);
}
NOTE 1 -- The class GameOfLife does not count neigbors ... each cell does its own counting. The next state is computed from these counts.
NOTE 2 -- The class GameOfLife does not update the display ... each cell updates it's own little piece of the screen.
THUS, there is no getter of Cell_t state, or next state, or living-neighbour count, or dead-neighbour count, etc.
With respect to this aspect of these two classes
The cohesion (of Cell_t) is functional, the most desirable.
The coupling (of GameOfLife_t to Cell_t) is 'none', also the most
desirable.
Changing the name or type of a Cell_t private data attribute has no
impact on any other code.
Oh, and a debug routine I often add (for another example):
std::string Cell_t dump() {
std::stringstream ss;
ss << // .... anything you want to 'dump' from this instance
return (ss.str());
}
I use the method name dump() to indicate an intent for a 'deeper' investigation of the activity of a specific Cell_t ... I have sometimes generated tabular data of state changes, with time stamps.
I often have a very similar method called show(), which typically provides a string for the user ...
These two examples, perhaps, illustrate the idea that a getter is simply bypassing an important aspect of the design process - naming what you are doing.
I believe the question stated in Problem could be modified. The question should not be "How can I avoid getters and setters?". This question is also related to other questions like "Should this method be a non-static member, static member, friend or helper?" or "Should this property be private or protected?". A better question to ask yourself is rather, "Who needs to access a particular property".
One way of writing classes which are easy to maintain is to limit the number of functions which have access to a specific property. This does not necessarily mean that no function should ever have access to a private property or that getters/setters should never be used. Take for example the class std::vector. Which can be simplified to something like this (with a lot of reservartions). The actual implementation of vector is normally much more sophisticated and may have different internal implementation but this simplified construction will be used to show a point.
template<class T, class Allocator<T> a = basic_allocator<T>>
class vector {
size_t sz;
size_t cap;
Allocator a;
T* elem;
// ... private methods
public:
// public methods and operators.
}
This class lets the developer access all elements in the internal array, where data is stored. This is done either via the operator [] (unchecked) or via the function at (checked). The developer have full rights to read or write to these elements. Without this access the vector class would be fairly useless and people would revert to use arrays instead. The class also provides getters to sz and cap via methods size() and capacity(). However sz and cap is otherwise seen as internal information and the developer is not allowed to change these directly. Instead the developer can use methods like push_back(), pop_back(), shrink_to_fit(), resize(), ... To add or remove data, manage allocated memory, etc ... The reason is that these operations requires some quite advanced memory handling and modifying these variables would cause leaks and/or crashes. Further, the developer does really not need to bother about these abstractions, since the developer only need the elements in the array.
So to conclude encapsulation is good and need to be considered. However this does not mean that the developer is never allowed to directly modify properties of some classes.

Retrieving values of collection from multiple classes, what's the correct way?

Before anything, thanks for reading!
I'm developing an application in C++ and I want an advice about a design issue. Let me explain:
The main class of my application has some collections, but other classes eventually need to get a value from one of those collections. Something like this:
class MainClass {
private:
// Collections are internally implemented as QHash
Collection<Type1> col1;
Collection<Type2> col2;
};
class RosterUnit {
public:
RosterUnit() {
/* This method needs to get a specific value from col1 and
initialize this class with that data */
}
};
class ObjectAction {
public:
virtual void doAction() = 0;
};
class Action1 : public ObjectAction {
public:
void doAction() {
// This needs a specific value from col2
}
};
class Action2 : public ObjectAction {
public:
void doAction() {
// This needs a specific value from col1
}
};
My first approach was passing the whole collection as parameter when needed, but it is not so good for ObjectAction subclasses, because I would have to pass the two collections and if I later create another subclass of ObjectAction and it needs to get an element from other collection (suppose col3), I would have to modify the doAction() signature of every ObjectAction subclass, and I think that is not too flexible. Also, suppose I have a Dialog and want to create a RosterUnit from there. I would have to pass the collection to the dialog just to create the RosterUnit.
Next I decided to use static variables in RosterUnit and ObjectAction that pointed to the collections, but I'm not very happy with that solution. I think it is not flexible enough.
I have been reading about design patterns and I first thought a Singleton with get functions could be a good choice, but after some more investigation I think it isn't a proper design for my case. It would be easier and more or less the same if I use global variables, which don't seem to be the right way.
So, could you give some advices, please?
Thank you very much!
As mentioned previously, Iterators are good for abstracting away the details of the Collection. But going this route implies that the objects that use the Iterators will need to know about what's inside the Collection. Meaning they will need to know how to decide which object in the Collection they need, thus increasing the coupling. (more details below in the Factory paragraph) This is something you need to consider.
Another approach would be to create accessor methods on the MainClass that take some sort of key and return an object from the Collection (findObject(key)). Internally the MainClass methods would search through the container(s) and return the appropriate object. To use this approach, you will however need access to the MainClass, either by dependancy injection as mentioned before, or possibly making it a Singleton (not recomended in this scenario, though).
With the info provided so far, it may even be better for your ObjectAction Factory to have a reference to the MainClass, and as a part of the ObjectAction creation logic, call the appropriate MainClass accessor and pass the result into the ObjectAction, thus decoupling the ObjectAction Objects from the MainClass.
You probably want to use iterators, they exist exactly for the purpose of abstracting away sequences from specific containers.
If your issue is how to pass the iterators to the code that needs them in the first place, do not give in to the temptation to use globals. It may look more convoluted if you have to pass parameters in, but your code is that much more decoupled for it. "Dependency Injection" is a good keyword if you want to read more about this topic.
I would also advise you to check out std::function or boost::function instead of inheriting from ObjectAction. Functional style is getting more common in modern C++, as opposed to how it's usually done in languages like Java.
There's not enough information here of what you are trying to do. You make it sound like 'at some point in the future, this statically created action needs this data that was left behind.' How does that make any sense? I would say either construct the actions with the data, as you would for instance with a Future or Callable), or have the command ask for the next piece of data, in which case you are just implementing a Work queue.
Sounds like you are trying to do something like a thread pool. If these actions are in any way related, then you should have then in some composing object, implementing something like the Template Method pattern, e.g. execute() is abstract and calls a few other methods in a fixed sequence and that cannot be overridden, the other methods must be (protocol enforcement).