I am trying to build an execution graph where each node can produce multiple outputs of different types and consume multiple inputs of different types. Data is transferred between the nodes via queues.
To connect 2 nodes, the input type of one node must be connected to the same output type of the other node. For example, trying to connect the int output of one node to the double input of another node should yield in a compilation error.
All nodes will derive from a base class that has a execute() method that reads from the different input types and writes into the different output types. Currently, I have something like this-
struct Node {
virtual void execute() = 0;
};
struct IntegerGeneratorNode: public Node {
void execute() {
while(some_condition_is_not_met) {
// write() will do std::queue<int>::push();
int_out.write(some_rand_integer);
}
}
Output<int> int_out;
};
struct FloatGeneratorNode: public Node {
void execute() {
while(some_condition_is_not_met) {
// write() will do std::queue<float>::push();
float_out.write(some_rand_float);
}
}
Output<float> float_out;
};
struct SinkNode: public Node {
void execute() {
while(some_condition) {
int val = int_inp.read(); // invokes queue<int>::front()+pop()
float f_val = float_inp.read();
// Do something with val and f_val.
}
}
Input<int> int_inp;
Input<float> float_inp;
};
Input<T> is a templated class that has a queue of type T. Output<T> is a templated class that has a pointer to a queue of type T. To connect 2 nodes, I do something like-
Node *int_node = IntegerGeneratorNode();
Node *float_node = FloatGeneratorNode();
Node *sink_node = SinkNode();
int_node.int_out.connect(sink_node.int_inp);
float_node.float_out.connect(sink_node.float_inpt);
std::thread int_thread([](Node *node){ node->execute(); }, int_node);
std::thread float_thread([](Node *node){ node->execute(); }, float_node);
std::thread sink_thread([](Node *node){ node->execute(); }, sink_node);
This works fine but I have another requirement- perform some operation on ALL the Input<T>s of a Node before the execute method is called - Input<T>::doSomePreProcessing(). As you can see, having named variables doesn't scale. You have to add a .doSomething on ALL the variables you have. I need some kind of looping.
One idea is to have a tuple of Input types and iterate the tuple using C++17 std::apply. But another major requirement I have is that the derived classes are client code and base class is framework code. All preprocessing must be done from the base class to lessen the burden the load on the derived classes. To do this I need to move the tuple to the base class like this-
template<typename T>
struct Node {
virtual void execute() = 0;
void doExecute {
preprocess(some_tuple);
execute();
}
T inputs() { return input_tuple; }
T input_tuple;
};
template<typename T>
struct SinkNode: public Node<T>{
...
};
// Call site.
SinkNode<std::tuple<int,float>> sink_node;
2 side-effects happened cos of this change
The base class is now templated and I can no longer have a common base class pointer which is required to invoke doExecute method on the nodes of the graph.
connect is hard to implement. Ideally what I am looking for is
template<typename T>
void connect(Node* src, Node* dest) {
std::get<T>(src.outputs()).connect(std::get<T>(dest.inputs()));
}
But since Node* is not available anymore, I can't do this.
How do I do all processing on the inputs in the base class yet have a common base class pointer? In other words not have it templated?
Several approaches come to mind:
Split off the virtual void execute() = 0 into a separate baseclass, from which you then derive the different, templated baseclasses.
Apply the Decorator Pattern: Just create a Node class that wraps another Node class. When the outer execute() is called, preprocess the input and then invoke the inner execute().
Use multiple inheritance. One base class might provide the execute() interface, another might provide the preprocessing interface. This is similar to the first variant, only that the two parts are not stacked on top of each other but rather next to each other on the same level.
Related
Consider I have a Plant class that has derived Fruit and Vegetable classes, and Fruit class has some more derived classes, like Orange and Apple, while Vegetable has derived Potato and Tomato. Assume, Plant has Plant::onConsume()=0; method:
class Plant
{
public:
virtual void onConsume(void)=0;
};
class Fruit:public Plant
{
};
class Orange:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Apple:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Vegetable:public Plant
{
};
class Potato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Tomato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Consumer
{
public:
void consume(Plant &p)
{
p.onConsume();
// Specific actions depending on actual p type here
// like send REST command to the remote host for Orange
// or draw a red square on the screen for Tomato
}
};
Suppose, I have a Consumer class with Consumer::consume(Plant) method. This "consume" method should perform different actions for different "Plants" instances/types, among calling Plant::onConsume() for any of "Plants". These action ain't directly related to the Plant class, require a lot of different additional actions and parameters, could literally be completely arbitrary, so cannot be implemented inside onConsume method.
What is the preferred method to implement this? As I understand, it is possible to implement some "Plant::getPlantType()=0" method, that would return plant type, but in this case I'm not sure what should it return. In case the returned value would be an enum, I'd need to change this enum each time I add a new derived class. And in any case, there's no control that multiple derived classes could return the same value.
Also, I'm aware there's a dynamic_cast conversion that returns nullptr if conversion could not be made, and typeid() operator that returns std::typeinfo (even with typeinfo::name()), which could be used in the switch() (it's just great for my case). But I'm afraid it could significally slow down the execution and make code heavier.
So, my question is, what is the preferred way in C++ to do that? maybe I just forgot about some simpler way to implement that?
A little update. Thank you for your explanations about inheritance, encapsulation etc! I supposed it's clear from my question, but it is not, I am sorry about that. So, please think about it, like I don't have an access to the whole Plant sources hierarchy, just need to implement this Consumer::onConsume(Plant). So I cannot add new specific methods in it. Or, also, it could be considered as a Plants library, that I have to write once, and make it usable for other devs. So, I could divide use cases/functionality into two parts: one that implemented "per class" in the Plant::onConsume() method, and second that is unknown yet and will differ depending on usage.
One option would be the visitor pattern, but this requires one function per type in some class. Basically you create a base class PlantVisitor with one Visit function per object type and pass add a virtual method to Plant that receives a PlantVisitor object and calls the corresponding function of the visitor passing itself as parameter:
class PlantVisitor
{
public:
virtual void Visit(Orange& orange) = 0;
virtual void Visit(Tomato& tomato) = 0;
...
};
class Plant
{
public:
virtual void Accept(PlantVisitor& visitor) = 0;
};
class Orange : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
class Tomato : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
This would allow you to do something like this:
class TypePrintVisitor : public PlantVisitor
{
public:
void Visit(Orange& orange) override
{
std::cout << "Orange\n";
}
void Visit(Tomato& tomato) override
{
std::cout << "Tomato\n";
}
};
std::vector<std::unique_ptr<Plant>> plants;
plants.emplace_back(std::make_unique<Orange>());
plants.emplace_back(std::make_unique<Tomato>());
TypePrintVisitor visitor;
for (size_t i = 0; i != plants.size(); ++i)
{
std::cout << "plant " << (i+1) << " is a ";
plants[i]->Accept(visitor);
}
Not sure the need for this does not indicate a design inefficiency though.
Btw: If you've got multiple visitors and do not necessarily want to implement logic for every single type in all of them, you could add default implementations in PlantVisitor that call the function for the supertype instead of specifying pure virtual functions.
Polymorphism is all about not having to know about a specific type. Usually your design is flawed if you discover having to detect a specific type explicitly.
At very first:
void Consumer::consume(Plant p)
does not work as intended! The Plant object is accepted by value, i. e. its bytes are copied one by one; however, only those of the Plant type, any others (those of derived types) are ignored and get lost within consume function – this is called object slicing.
Polymorphism only works with references or pointers.
Now assume you want to do something like the following (incomplete code!):
void Consumer::consume(Plant& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
if(/* p is apple */)
{
appleSpecific();
}
else if(/* p is orange */)
{
orangeSpecific();
}
generalCode2();
}
You don't want to decide yourself upon type, you let the Plant class do the stuff for you, which means you extend its interface appropriately:
class Plant
{
public:
virtual void onConsume() = 0;
virtual void specific() = 0;
};
The code of the consume function will now be changed to:
void Consumer::consume(Plant const& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
p.specific();
generalCode2();
}
You'll do so at any place you need specific behaviour (and specific is just a demo name, chose one that describes nicely what the function actually is intended to do).
p.onConsume();
generalCode1();
p.specific1();
generalCode2();
p.specific2();
generalCode3();
p.specific3();
generalCode4();
// ...
Of course you need now to provide appropriate implementations in your derived classes:
class Orange:public Fruit
{
void onConsume() override
{ }
void specific() override
{
orangeSpecific();
}
};
class Apple:public Fruit
{
void onConsume() override
{ }
void specific() override
{
appleSpecific();
}
};
Note the addition of override keyword, which protects you from accidentally creating overloaded functions instead actually overwriting in case of signature mismatch. It helps you, too, to locate all places of necessary changes if you discover having to change the function signature in the base class.
I have a c++ class:
Class farm {
...
protected:
vector<ff_node*> workers;
};
//ff_node an abstract method representing a single thread
class ff_node {
protected:
//svc is the method to encapsulate a sequential function
void* svc(void *)=0;
};
Class farm_withMoreWorkers: public farm {
void addWorker(){
ff_node *newWorker;
newWorker=new ff_node();// rather than adding ff_node make the instance type as that of type workers since ff_node is abstract
farm:: workers.push_back(newWorker);
}
};
The class ff_node is abstract . In order to add one more worker, I need to create a new instance whose type is the same as the others (all of the workers are of the same type)
Is there a way to get the specific type of (one of the) workers and create an instance of that type?!
Create a pure virtual clone function in the base class and override it in every derived class.
class ff_node
{
public:
virtual ff_node* clone() = 0;
};
class ff_child : public ff_node
{
public:
ff_node* clone() override {new ff_child;}
};
Now, given a ff_node* node, you can create another instance of the same runtime type by calling node->clone().
You gave very little info, so I'm speculating as to what you actually want. Suppose there is an abstract (pure virtual) class
class worker { /* define some useful virtual interface */ };
and you want to use several polymorphism to use several differernt workers. Then you best keep them in a vector of unique_ptr, so that at the end of the vector's scope the workers are automatically deleted. You can add a new worker by directly constructing it from arguments provided by the user. Since the type of the new worker may not even be known at the time of definition of the farm, this functionality must be provided as template. For example
class farm
{
std::vector<std::unique_ptr<worker>> workers; //
public:
// constructs new worker of type Worker with arguments provided
template<typename Worker, typename... Args>
void add_worker(Args&&...args)
{ workers.emplace_back(new Worker(std::forward<Args>(args)...)); }
};
and use it like this
struct builder : public worker
{
builder(string const&, const widget*, some_type);
/* ... */
};
farm the_farm;
widget w( /* ... */ );
some_type x;
the_farm.add<builder>("the new builder", &w, x);
Note that in the call to farm::add() only the first template parameter must be provided, the others will be deduced from the function arguments.
I'm writing an intrusive linked list
class ListAlgorithm {
ListNode& next(ListNode& n) {
//returns an object of type ListNode linked to n.
}
};
Users usually want to add some features (such as some additional data) on ListNode like this:
class UserNode : public ListNode {
void operationOnUserData();
int userData;
};
Then users have to downcast ListNode returned by 'next' into UserNode. It is inconvenient. Thus, I tried to make ListAlgorithm a template class :
//U extends ListNode
template<class U>
class ListAlgorihtm {
U& next(U& u);
};
But then I have to upcast u into ListNode inside the method 'next' because class U could accidentally hide some members of ListNode that ListAlgorithm uses. This is error-prone because I could forget the upcast and compiler will not warn about that. I have to downcast ListNode into U again for the return value but it is safe because 'next' takes an instance u of U and the return value is something from u.
Another trial is
//U extends ListNode
template<class U>
class ListAlgorhtm {
U& next(ListNode& n);
};
In this case, the upcast problem is not there, but I have to downcast ListNode into U for the return value and it is not safe because it is not sure that n is an instance of U. It could be an instance of another type extending ListNode.
What is the best solution in this case? I think this is a very elementary design problem and I'd like to know what kind of material I have to study for basic OO design like this.
Your actual problem here is that you allow users to subclass ListNode and mess with its semantics by adding arbitrary data and operations to ListNode objects through subclassing. This therefore makes it necessary for the user to interpret the ListNode& return values of actual ListNode methods as something that those return values are not, semantically speaking.
This problem of a semantic nature is reflected in how tedious your code suddenly becomes, with casts and templating of an unrelated class (ListAlgorithm) which is due to your problem "propagating" and infecting other parts of your code.
Here's a solution: a ListNode object should not be allowed to also be a UserNode object. However, it should be allowed to have, to carry with it a UserData object that can be retrieved and manipulated.
In other words, your list becomes a simple container template, like std::list, and the users can specify the operations and data members that they need as part of the definition of the class they use as the template argument.
class IListNode
{
public:
// whatever public methods you want here
protected:
// pure virtual methods maybe?
};
class ListNode : public IListNode
{
// List node class, no data
};
template<class UserDataType>
class ListNodeWithData : public IListNode
{
private:
UserDataType data;
public:
ListNodeWithData <UserDataType>(UserDataType &data) :
data(data)
{ }
const UserDataType& getData() {
return data;
}
};
class ListAlgorithm
{
public:
template<class UserDataType>
ListNodeWithData<UserDataType>& next(const ListNodeWithData<UserDataType>& node) {
// Do stuff
}
ListNode& next(const ListNode& node) {
// Do stuff, which may be very similar to the stuff done above
// in which case you may want to prefer to just define the
// method below, and remove this one and the one above:
}
// You should define either this method or the two above, but having
// them all is possible too, if you find a use for it
IListNode& next(const IListNode& node) {
// Do generic stuff
}
};
As far as the size of the resulting classes is concerned, I just know it will increase if you use virtual methods in IListNode.
As far as the issue you raise goes, any time you want to operate on members of a class and avoid hiding by a derived class, just make sure your operations are on the base, so
template<class U>
class ListAlgorihtm {
public:
U& next(U& u) {
return static_cast<U&>(return nextNode(u));
}
private:
ListNode& nextNode(ListNode& n);
};
That said, you have a lot of options for this problem set. The Boost library has an "intrusive" library that embeds node information either as base_hook (as a base of the user data) or member_hook (as a member of the class, which avoids some of the problems you describe). Check it out at http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive.html.
My question is about merging 2 techniques:
Call recursively to super functions
Call recursively to the same function
Suppose a root class that has a recursive function (foo), and a extended class that override this function ( foo): the override function must call super::foo, but require to perform other operations before to call recursively.
I will try an example (it is only an example, and I know there is non-recursive way to solve this problem)
class Node
{
public:
// must be override
virtual int getNumValues()
{
if (parent) return parent->getNumValues() + 3;
else return 3;
}
protected:
Node *parent;
private:
int values[3];
};
class ExtNode: Node
{
public:
//#override
virtual int getNumValues()
{
int aux = Node::getNumValues(); //but need to avoid recursion here.
if (parent) return parent->getNumValues() + aux + 2;
else return aux + 2;
}
private:
int extValues[2];
};
So what I would is:
I may change both classes: Node and ExtNode.
I would not to copy the code from the first class method to the second to avoid Super call (the class chain may be long)
The recursive call should probably be done by the childest class
I am trying some ideas, but they seem poor programming practice or not possibles:
// In Node class
...
virtual int getNumValues()
{
if (parent && !isNodeObject(this)) return parent->getNumValues()+3;
else return 3;
}
bool isNodeObject( Node *ob)
{
//return if ob is instance of Node (and not an extended class). How?
}
I have also tried with optional parameters:
// In Node class
...
virtual int getNumValues( bool recursion = true)
{
if (parent && recursion) return parent->getNumValues()+3;
else return 3;
}
// In ExtNode class
...
virtual int getNumValues( bool recursion = true)
{
int aux = Node::getNumValues(false );
if (parent && recursion) return parent->getNumValues() + aux + 2;
else return aux + 2;
}
What is the best programming practice for that?
EDIT 1: Explanation of the real problem I am trying to resolve (asked from Joachim Pileborg)
I am creating a User interface library, that is, a set of classes and function to create easily widgets like frame, buttons, input texts, etc.
I have created a basic (root class) widget with most general features, a "Visible" widget to implement all generic functions for widgets that has a visible part, and soo on.
There are also some containers, like frames, layout and windows.
Now come the hard part: there is a function "updateStyle" that is supposed to update at once all the graphic part of the widget (and redraw it): this function call recursively to super class to perform more generic features, and also has to call recursively to containers to propagate changes (dimensions and positions of widgets may change)
Each widget is supposed to work "as this" and also to be extendable, that is why these requirements.
Code is extensive (about 8k lines) and has a lot of other features, so no point to copy here
the code.
It looks like you are searching for the template method pattern:
in the base class, implement a nonvirtual method that outlines the general behavior of the function.
define (abstract) virtual methods that define the special behavior parts inside that function
in derived classes, override the special behavior
class Node
{
public:
int getAllNumValues()
{
int allNumValues = getNumValues();
if (parent) allNumValues += parent->getAllNumValues();
return allNumValues;
}
protected:
virtual int getNumValues() {
return 3;
};
private:
Node *parent;
int values[3];
};
class ExtNode: Node
{
protected:
//#override
virtual int getNumValues()
{
return 2 + Node::getNumValues(); //but need to avoid recursion here.
}
private:
int extValues[2];
};
in case of your update functionality I'd suggest to have a template method update that does the recursive updating of your composite pattern, and another method updateThis that does updating of only the single object.
According to Herb Sutter's article: Virtuality, we should prefer to make virtual functions private. This implies that we should try to avoid calling "super" versions and instead make the base class do the work.
Here's an example:
class Node
{
public:
int getNumValues()
{
int result = 3 + DoGetNumValues();
if (parent)
result += parent->getNumValues();
return result;
}
private:
Node *parent;
int values[3];
virtual int DoGetNumValues() {return 0;}
};
class ExtNode : public Node
{
private:
int extValues[2];
int DoGetNumValues() override sealed {return 2 + GetMoreValues();}
virtual int GetMoreValues() {return 0;}
};
class Derived : public ExtNode
{
int GetMoreValues() override {return 1;}
};
For the first example,
Node::getNumValues() computes some function of a tree.
ExtNode::getNumValues() computes another function of a tree. Either result of
ExtNode::getNumValues() is function of ( Node::getNumValues(), tree ) or it depends on tree only.
For UI problem,
Think about chain of responsibility design pattern. Forward update request up to the root node, which in its turn initiates tree traversal to update all nodes starting from root.
One way to deal with this is to make the function non virtual, then explicitly call in each override the super classe's function (similar to the constructor).
Having the method non-virtual means that each class that is inherited will have it's own implementation of the method, so you won't overwrite the classe's parent code by writing a implementation of the function.
The downside will be that you will have to call the function via a pointer that is explicitly of a certain type, thus forcing you to know the type.
To avoid this drawback, make a virtual function that calls the required recursive function, and use that function instead.
As a side note, non-virtual functions should be avoided.
Here's a sample code
class base
{
public:
int doStuff()
{
printf(" base called ");
return 0;
}
};
class ext : public base
{
public:
int doStuff()
{
base::doStuff();
printf(" ext called ");
return 0;
};
};
class ext2 : public ext
{
public:
int doStuff()
{
ext::doStuff();
printf(" ext 2 called");
return 0;
};
};
void runTest()
{
base* ptr = new ext2();
ptr->doStuff();
ext2* recast = (ext2*) ptr;
recast->doStuff();
}
For the code above, the output will be " base called base called ext called ext2 called".
If you declare the doStuff function virtual in the base class (thus making it virutal for every child class) the output will be " base called ext called ext2 called base called ext called ext2 called".
So suppose I have a tree class like this in c++
class Node{
void addChild(Node*);
/*obvious stuff*/
protected:
Node* parent;
vector<Node*> children
}
class specialNode : public Node{
void addChild(specialNode*);
/*obvious stuff*/
/*special stuff*/
}
Now whenever I access the children in specialTree, I obviously get Node*, not specialNode*.
But this specialNode* has member variables and functions that Node doesn't have.
I can force specialNode to only have take specialNode as children and otherwise break in compile time,
but I still get Node* when accessing children/parent, and I have to cast it whenever I want to use special functions, even in specialNode functions.
Is there any clever, or just any better way to go about this?
Other than literally casting every time?
If you only need SpecialNode objects in your tree (and just want to encapsulate all generic tree functionality in Node) you can make Node a so called "mix-in" class like
template <class N>
class Node : public N {
public:
void addChild(Node<N>*);
protected:
Node<N>* parent;
vector<Node<N>*> children;
};
class SpecialNodeBase {
// Here comes all "special" data/methods for your "special" tree
};
typedef Node<SpecialNodeBase> SpecialNode;
After that you can construct a tree of SpecialNode objects and use all methods from SpecialNodeBase as well as additional tree-managing functions from Node
Because addChild function in your child class is not polymorphism, make it virtual, but overloading functions across base/child members is not allowed, so we have to change the addChild parameter in the child class:
class Node{
virtual void addChild(Node*);
...
}
class specialNode : public Node{
virtual void addChild(Node*);
...
}
Now, it should work.
If you want to access to the childeren variable from the child class (specialNode class), you should cast it. For example:
specialNode* var = static_cast<specialNode*>(children[i]);
Since we declared addChild as a virtual function, then we should use dynamic_cast instead of static_cast if we aren't sure that children[i] is always an instance of specialNode class, and thus it is better to use dynamic_cast:
specialNode* var = dynamic_cast<specialNode*>(children[i]);
if(var != NULL)
{
//...
}
If I understand correctly, the "Mix-in" class solution won't allow you to call addChild from functions implemented by SpecialNodeBaseClass.
You can actually do the following:
template <class recursiveT>
class Base {
public:
Base(dataType data) { populate children with data; }
void addChild() { something base class appropriate; }
protected:
std::vector<recursiveT> children;
};
class Derived: public Base<Derived> {
public:
/* note: the constructor here will actually call the
constuctor of the base class */
Derived(dataType data) : Base<Derived>(data) {}
/* other special functions go here. */
};
This may look a little crazy, but it compiles cleanly for me on several GCC versions so I'm inclined to believe it's not totally wrong-headed. You should now be able to call the functions of Base from inside Derived.
You will definitely have to cast the Node * to a specialNode * at some point, but you can make this clean and easy to manage by doing this in only one place. You could add a member function, say getParent and override it in specialNode, like this:
class Node {
...
virtual Node *getParent() {
return parent;
}
};
class specialNode : public Node {
...
specialNode *getParent() {
return dynamic_cast<specialNode *>(parent);
}
};
Of course, this is assuming that specialNodes always have other specialNodes as parent/children. If you mix Nodes and specialNodes, this obviously won't work.