i'm developing the people evacuation simulator. At start, it will load a tree-like building structure data (floor/room/wall, etc.) from XML file, load the initial configuration of people, read user-defined moving model parameters and start simulation. E.g. for each man at each model step i need to find all geometry objects near him, and select the closest path to path to exit from the building - as fast as possible.
So, i need to load a clear OOP-way to represent building, where people will move.
I stuck with this (just example):
class Aperture
{
...
public:
virtual QRectF extent() = 0;
virtual QString description() const = 0;
// other common for all apertures methods
private:
int m_srcRoomID;
int m_dstRoomID;
// other generic aperture properties
};
class Window: Aperture
{
...
public:
virtual void extent() override;
virtual QString description() override;
// other overrides
private:
EGlassType m_glassType;
bool m_bOpenable;
// other window-specific properties
};
// and other descendants: Door, CompositeDoor and so on
The problem: i want to store all building apertures in one collection as pointers to abstract base Aperture, and use only base virtual functions without any casting to derived Apertures.
BUT: during evacuation various Aperture properties may change, so i need to modify them in the type-dependent way. I can't make this functionality common and place it to the base class: window haven't closer, antifire door don't afraid of fire - but others do, and so on. May be there is a way (e.g. design pattern) to dynamically store/add/remove these properties? or just avoid subclassing at all, because complete hierarchy of Building items is very compicated and clunky.
You could add a virtual function to set the properties in the base class Aperture, like
virtual void update(vector) = 0; or
virtual void update(...) = 0;
Well, the entity deciding to close the door needs to know that it can be closed and it should even consider changing that state. Here are some options:
Make the object decide for itself in a genericish virtual method (something like Aperture::update, Aperture::interactWithFire, Aperture::iteractWithPerson or similar).
Use the Visitor pattern, i.e. create virtual Aperture::visit that will call appropriately overloaded method back on the visitor. That allows you to define interaction methods only for the combination of objects for which it makes sense.
Use "interfaces", say IClosable on anything that can be closed like Door and in appropriate place IClosable * closable = dynamic_cast<IClosable *>(apperture); if(closable) { /* consider whether it should be closed */ } Actually you'd probably use such interfaces with the visitor pattern too to reduce the number of necessary overloads.
If any, or any combination of this, works for you, the object oriented approach is viable.
Related
Context
The context is composed by three classes:
abstract parent (e.g. Player)
child (e.g. TapePlayer)
a holder (e.g. MyMachine)
The holder has a member variable that is a shared_ptr<...> to the parent class and a setter for it accepts shared_ptr<...>s of children classes.
My getter looks something like this
shared_ptr<Parent> getChildPtr() {
return parentPtr;
};
but it returns a pointer to the parent, and cannot access child methods.
If I want to do something like the following
holder.getChildPtr()->childMethod();
// ERROR! No member named 'childMethod' in 'Parent'
How should I implement the getter to get the pointer to the child instead of the parent class?
Code
The whole code looks something like this:
class Player {
public:
Player(){};
virtual ~Player{};
virtual void play() = 0;
}
class TapePlayer : public Player {
public:
TapePlayer(){};
virtual ~TapePlayer{};
void play() { ... };
void rewind() { ... };
}
class MyMachine {
public:
MyMachine(); //
~MyMachine();
void setPlayer(shared_ptr<Player> p) {
playerPtr = p;
}
shared_ptr<Player> getPlayer() {
return playerPtr;
};
private:
shared_ptr<Player> playerPtr;
}
MyMachine machine; // the holder
shared_ptr<TapePlayer> tapePtr(new TapePlayer()); // pointer to child
machine.setPlayer(tapePtr); // set holder with pointer to child
machine.getPlayer()->rewind(); // -- ERROR! No member named 'rewind' in 'Player'
// if I want to get the player of that machine to rewind I need
// to dynamic_cast<TapePlayer>() ...
I'm pretty sure there's a better way of doing this than casting to children types. Any ideas?
EDIT
This was a very simplified example. What I'm actually trying to do is this:
My holder class is named Clip. A clip plays something, be it an
image, a video, a sequence of images, some kind of processing with
OpenCv, a vector shape... anything that can be displayed.
All these types of things are Players.
I don't care what type of player the clip holds. I just want it to show it to me. But, some players need tweaking at runtime, like the OpenCv one, that needs tweaking parameters for optimal processing. I cannot implement all methods of all subclasses in the parent class, that would make no sense to me. Why does a video need to have the methods for tweaking OpenCv parameters?
All I need is that both have 'playable' methods, and be able to store them in a map<string, PlayerPtr> to access them at any time or change the player the clip is holding.
The point is that this kind of ruins the polymorphism - even with dynamic_cast, you still need to check that the result is not 0 (i.e. check the actual type) and as you might already know, dynamic_cast is famous for being very slow (and requiring RTTI information built in the executable).
Is there any reason you couldn't add a pure virtual rewind() method to your Player interface? Then you'd just call it and the inherited class could do whatever it decides in that case. Other subclasses might implement it as empty (or it can be even empty by default in the Player itself, so that the subclasses do not have to implement it if they don't need to). Perhaps even some more "generic" virtual function like reset(), restart() etc. which would just call rewind() for the TapePlayer under the hood.
You can of course go even more fancy with more complex solutions like visitor/observer (TapePlayer being RewindObserver and observing a rewind event) etc.
EDIT:
So to address the edit comments - if the different types need tweaking, then again, you can just have a single virtual method tweak() (pure or with default empty impl) and do whatever tweaking is needed. Otherwise you'd anyway end up with a long list of ifs and call tweak methods depending on the actual type.
If the tweaking requires some special parameters, then the situation can be difficult ... one option could be to have a tweaking parameters interface (and call the tweak method with that), but if the params can't be unified you'd need a dynamic cast in the tweak method anyway to cast to the correct params type (this basically leads to double dispatch which in C++ requires casting at some point) ... but anyway that would still require to create different param classes in the calling site which is not that nice.
It also depends when you actually need to setup the tweaking parameters - if it is enough to setup everything when creating the instance (and the tweaking params do not change afterwards), or if it is needed to change them later on. If only needed to setup at startup, then you can have factory classes for the different object types and the factory can setup the params.
(technically you could handle even the necessity of changing the params a similar way, by keeping the setting object types for various player types, the players would keep reference to them as well, assigned when the objects are created, and once they need to be changed, you'd change the settings and call tweak() or update() or similar func to inform the objects that some setting changed and needs to be re-applied)
I have a collection of classes and functions which can interact with one another in rich and complex manners. Now I am devising an architecture for the top-level layer coordinating the interaction of these objects; if this were a word processor (it is not), I am now working on the Document class.
How do you implement the top-level layer of your system?
These are some important requirements:
Stand-alone: this is the one thing that can stand on its own
Serializable: it can be stored into a file and restored from a file
Extensible: I anticipate adding new functionality to the system
These are the options I have considered:
The GOF Mediator Pattern used to define an object that encapsulates how a set of objects interact [...] promotes loose coupling by by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
The problem I see with mediator is that I would need to subclass every object from a base class capable of communicating with the Mediator. For example:
class Mediator;
class Colleague {
public:
Colleague(Mediator*);
virtual ~Colleague() = default;
virtual void Changed() {
m_mediator->ColleagueChanged(this);
}
private:
Mediator* m_mediator;
};
This alone makes me walk away from Mediator.
The brute force blob class where I simply define an object and all methods which I need on those objects.
class ApplicationBlob {
public:
ApplicationBlob() { }
SaveTo(const char*);
static ApplicationBlob ReadFrom(const char*);
void DoFoo();
void DoBar();
// other application methods
private:
ClassOne m_cone;
ClassTwo m_ctwo;
ClassThree m_cthree;
std::vector<ClassFour> m_cfours;
std::map<ClassFive, ClassSix> m_cfive_to_csix_map;
// other application variables
};
I am afraid of the Blob class because it seems that every time I need to add behaviour I will need to tag along more and more crap into it. But it may be good enough! I may be over-thinking this.
The complete separation of data and methods, where I isolate the state in a struc-like object (mostly public data) and add new functions taking a reference to such struct-like object. For example:
struct ApplicationBlob {
ClassOne cone;
ClassTwo ctwo;
ClassThree cthree;
std::vector<ClassFour> cfours;
std::map<ClassFive, ClassSix> cfive_to_csix_map;
};
ApplicationBlob Read(const char*);
void Save(const ApplicationBlob&);
void Foo(const ApplicationBlob&);
void Bar(ApplicationBlob&);
While this approach looks exactly like the blob-class defined above, it allows me to physically separate responsibilities without having to recompile the entire thing everytime I add something. It is along the lines (not exactly, but in the same vein) of what Herb Sutter suggests with regards to preferring non-member non-friends functions (of course, everyone is a friend of a struct!).
I am stumped --- I don't want a monolith class, but I feel that at some point or another I need to bring everything together (the whole state of a complex system) and I cannot think of the best way to do it.
Please advise from your own experience (i.e., please tell me how do you do it in your application), literature references, or open source projects from where I can take some inspiration.
Sorry for the lack of a better title; I couldn't think of a better one.
I have a class hierarchy like the following:
class Simulator
{
public:
virtual void simulate(unsigned int num_steps);
};
class SpecializedSimulator1 : public Simulator
{
Heap state1; Tree state2; // whatever
public:
double speed() const;
void simulate(unsigned int num_steps) override;
};
class SpecializedSimulator2 : public Simulator
{
Stack state1; Graph state2; // whatever
public:
double step_size() const;
void simulate(unsigned int num_steps) override;
};
class SpecializedSubSimulator2 : public SpecializedSimulator2
{
// more state...
public:
// more parameters...
void simulate(unsigned int num_steps) override;
};
class Component
{
public:
virtual void receive(int port, string data);
virtual void react(Simulator &sim);
};
So far, so good.
Now it gets more complicated.
Components can support one or more types of simulation. (For example, a component that negates its input may support Boolean circuits as well as continuous-time simulation.) Every component "knows" what kinds of simulations it supports, and given a particular kind of simulator, it queries the simulator (via dynamic_cast or double dispatch or whatever means are appropriate) to find out how it needs to react.
Here's where it gets tricky:
Some Components (say, imagine a SimulatorComponent class) themselves need to run sub-simulations inside of them. Part of this involves inheriting some properties of outer simulations, but potentially changing a few of them. For example, a continuous-time sub-simulator might want to lower its step size for its internal components in order to get better accuracy, but otherwise keep everything else the same.
Ideally, SimulatorComponent would be able to inherit from a class (say, SpecializedSimulator2) and override some subset of its properties as desired. The trouble, though, is that it has no idea whether the outer simulator's most-derived type is a SpecializedSimulator2 -- it may very well be the case that SimulatorComponent is running inside a more specialized simulator than that, like a SpecializedSubSimulator2! In that case, sub-components of SimulatorComponent would need to be able to somehow get access to the properties of SpecializedSubSimulator2 that they might need to access, but SimulatorComponent itself would not (and should not) be aware of these properties.
So, we see we can't use inheritance here.
Since the only means in C++ for "discovering" sub-interfaces like this is dynamic_cast, that means the sub-components must be able to directly access the outer simulator themselves, in order to run dynamic_cast on them. But if they do this, then SimulatorComponent can't intercept any of the calls.
At this point, I'm not sure what to do. The problem isn't impossible to solve, obviously -- I can think of some solutions (e.g. hierarchical key/value dictionary maintained at run-time) -- but the solutions involves some massive tradeoffs (e.g. less compile-time checking, performance loss, etc.) and make me wonder what I should be doing.
So, basically: how should I approach this problem? Is there a flaw in my design? Should I be solving this problem differently? Is there a design pattern for this that I'm just not aware of? Any tips?
I'll try to give a partial advice. For the situation in which you need to use a simulator inheriting properties from some parent then a cloning function could be the solution. This way you can ignore what actually the original simulation was, but anyway you end up with a new one with the same props.
It may just require some basic properties (like the simulation time step) which means you need to dynamic_cast to some intermediate class in your simulator hierarcy, but not exactly spot the right one.
I have an collection of objects which represents a model of a system. Each of these objects derives from a base class which represents the abstract "component". I would like to be able to look at the system and choose certain behaviours based on what components are present and in what order.
For the sake of argument, let's call the base class Component and the actual components InputFilter, OutputFilter and Processor. Systems that we can deal with are ones with a Processor and one or both filters. The actual system has more types and more complex interaction between them, but I think this will do for now.
I can see two "simple" ways to handle this situation with a marshalComponentSettings() function which takes one of the collections and works out how to most efficiently set up each node. This may require modifying inputs in certain ways or splitting them up differently, so it's not quite as simple as just implementing a virtual handleSettings() function per component.
The first is to report a enumerated type from each class using a pure virtual function and use those to work out what to do, dynamic_cast'ing where needed to access component specific options.
enum CompType {
INPUT_FILTER,
OUTPUT_FILTER,
PROCESSOR
}
void marshal(Settings& stg)
{
if (comps[0].type() == INPUT_FILTER)
setUpInputFilter(stg); //maybe modified the stg, or provides other feedback of what was done
// something similar for outputs
setUpProcessor(stg);
}
The second is to dynamic_cast to anything that might be an option in this function and use the success of that or not (as well as maybe the cast object if needed) to determine what to do.
void marshal(Settings& stg)
{
if (InputFilter* filter = dynamic_cast<InputFilter*>(comp[0]))
setUpInputFilter(stg); //maybe modified the stg, or provides other feedback of what was done
// something similar for outputs
setUpProcessor(stg);
}
It seems that the first is the most efficient way (don't need to speculatively test each object to find out what it is), but even that doesn't quite seem right (maybe due to the annoying details of how those devices affect each other leaking into the general marshaling code).
Is there a more elegant way to handle this situation than a nest of conditionals determining behaviour? Or even a name for the situation or pattern?
Your scenario seems an ideal candidate for the visitor design pattern, with the following roles (see UML schema in the link):
objectStructure: your model, aka collection of Component
element: your Component base class
concreteElementX: your actual components (InputFilter, OutputFilter, Processor, ...)
visitor: the abstract family of algorithms that has to manage your model as a consistent set of elements.
concreteVisitorA: your configuration process.
Main advantages:
Your configuration/set-up corresponds to the design pattern's intent: an operation to be performed on the elements of an object structure. Conversely, this pattern allows you to take into consideration the order and kind of elements encountered during the traversal, as visitors can be stateful.
One positive side effect is that the visitor pattern will give your desing the flexibility to easily add new processes/algortihms with similar traversals but different purpose (for example: pricing of the system, material planning, etc...)
class Visitor;
class Component {
public:
virtual void accept(class Visitor &v) = 0;
};
class InputFilter: public Component {
public:
void accept(Visitor &v) override; // calls the right visitor function
};
...
class Visitor
{
public:
virtual void visit(InputFilters *c) = 0; // one virtual funct for each derived component.
virtual void visit(Processor *c) = 0;
...
};
void InputFilter::accept(Visitor &v)
{ v.visit(this); }
...
class SetUp : public Visitor {
private:
bool hasProcessor;
int impedenceFilter;
int circuitResistance;
public:
void visit(InputFilters *c) override;
void visit(Processor *c) override;
...
};
Challenge:
The main challenge you'll have for the visitor, but with other alternatives as well, is that the setup can change the configuration itself (replacing component ? change of order), so that you have to take care of keeping a consitent iterator on the container while making sure not to process items several time.
The best approach depends on the type of the container, and on the kind of changes that your setup is doing. But you'll certainly need some flags to see which element was already processed, or a temporary container (either elements processed or elements remaining to be processed).
In any case, as the visitor is a class, it can also encapsulate any such state data in private members.
My GUI project in Qt has a lot of "configuration pages" classes which all inherit directly from QWidget.
Recently, I realized that all these classes share 2 commons slots (loadSettings() and saveSettings()).
Regarding this, I have two questions:
Does it make sense to write a intermediate base abstract class (lets name it BaseConfigurationPage) with these two slots as virtual pure methods ? (Every possible configuration page will always have these two methods, so I would say "yes")
Before I do the heavy change in my code (if I have to) : does Qt support virtual pure slots ? Is there anything I should be aware of ?
Here is a code example describing everything:
class BaseConfigurationPage : public QWidget
{
// Some constructor and other methods, irrelevant here.
public slots:
virtual void loadSettings() = 0;
virtual void saveSettings() = 0;
};
class GeneralConfigurationPage : public BaseConfigurationPage
{
// Some constructor and other methods, irrelevant here.
public slots:
void loadSettings();
void saveSettings();
};
Yes, just like regular c++ pure virtual methods. The code generated by MOC does call the pure virtual slots, but that's ok since the base class can't be instantiated anyway...
Again, just like regular c++ pure virtual methods, the class cannot be instantiated until the methods are given an implementation.
One thing: in the subclass, you actuallly don't need to mark the overriden methods as slots. First, they're already implemented as slots in the base class. Second, you're just creating more work for the MOC and compiler since you're adding a (tiny) bit more code. Trivial, but whatever.
So, go for it..
Only slots in the BaseConfigurationPage
class BaseConfigurationPage : public QWidget
{
// Some constructor and other methods, irrelevant here.
public slots:
virtual void loadSettings() = 0;
virtual void saveSettings() = 0;
};
class GeneralConfigurationPage : public BaseConfigurationPage
{
// Some constructor and other methods, irrelevant here.
void loadSettings();
void saveSettings();
};
Others have explained the mechanics of virtuals, inheritance and slots, but I thought I'd come back to this part or question:
Does it make sense to write a intermediate base abstract class ... with these two slots as virtual pure methods ?
I would say that that only makes sense if you have a use for that abstraction, or in other words, if you have code that operates on one or more BaseConfigurationPages without caring about the actual type.
Let's say your dialog code is very flexible and holds a std::vector<BaseConfigurationPage*> m_pages. Your loading code could then look like the following. In this case, the abstract base class would make sense.
void MyWizard::loadSettings()
{
for(auto * page : m_pages)
{
page->loadSettings();
}
}
But, on the other hand, let's say that your dialog is actually pretty static and has IntroPage * m_introPage; CustomerPage * m_customerPage; ProductPage * m_productPage;. Your loading code could then look like the following.
void MyWizard::loadSettings()
{
m_introPage->loadSettings();
m_customerPage->loadSettings();
m_productPage->loadSettings();
}
In this scenario, BaseConfigurationPage gains you absolutely nothing. It adds complexity and adds lines of code, but adds no expressive power and doesn't guarantee correctness.
Without more context, neither option is necessarily better.
As students or new programmers we are typically taught to identify and abstract away repetition, but that's really a simplification. We should be looking for valuable abstractions. Repetition may hint at a need for abstraction or it may just be a sign that sometimes implementations have patterns. And introducing an abstraction just because a pattern is noticed is a pretty common design trap to fall into.
The design of Dolphin and the design of Shark look a lot alike. One might be tempted to insert a TorpedoShapedSwimmer base class to capture those commonalities, but does that abstraction provide value or might it actually add unnecessary friction when it later comes time to implement breathe(), 'lactate()orgrowSkeleton()`?
I realise this is a long rant about a sub-question based on some simple example code, but I've recently run into this pattern several times at work: baseclasses that only capture repetition without adding value, but that get in the way of future changes.