Remove dynamic_cast in derived class of tree node - c++

I have a class which is a node of a tree, called Node. I need to create a DerivedNode class type which has some extra functionality. The problem is that Node has a vector of Node* as a member variable, so when DerivedNode inherits from Node, it inherits this vector. I've created a basic example showing the issue:
#include <iostream>
#include <vector>
class Node {
public:
Node(int value_) : value(value_) {}
int foo() { return value; }
virtual void add(Node* new_node) {
children.push_back(new_node);
}
protected:
std::vector<Node*> children;
int value;
};
class DerivedNode : public Node {
public:
DerivedNode(int value_) : Node(value_) {}
int bar() { return value*2; }
// Ensures we only add children of type DynamicNode*
virtual void add(DerivedNode* new_node) {
children.push_back(new_node);
}
void print() {
for (size_t i = 0; i < children.size(); ++i) {
std::cout << dynamic_cast<DerivedNode*>(children[i])->bar() << std::endl;
}
}
};
int main() {
DerivedNode* child_a = new DerivedNode(5);
DerivedNode* child_b = new DerivedNode(6);
DerivedNode parent(1);
parent.add(child_a);
parent.add(child_b);
parent.print();
delete child_a;
delete child_b;
}
My question is, how can I do this without the dynamic_cast? My actual code is far more complex which means that there are dynamic casts everywhere.

First add function in derived class is totally useless, it does not override add function from base class, it overloads it. In such way you still can add Node*'s to the derived class. To prevent this you should override add(Node*) as private.
If you does not like dynamic cast, you may use static cast instead
or
You may have virtual bar in base class that does not do anything
or
you can cast the vector itself (the whole thing) and assign to reference or pointer to std::vector DerivedNode*

You can't have it both ways. You either have IS-A principle reflected in the design of your classess, or you don't. If DerivedNode is Node, than the vector of Nodes should be indistinguishable from vector of DerivedNodes - and no casts are neccessary. If this can not be achieved, that you simply can not use vector of base pointers.
Any dynamic_cast in production code for me is a hard block for any review, as it clearly violates the basic design principles.

Related

Calling parent function from another function using child C++

So I have a parent Class which is:
class Node
{
public:
Node();
void setParentNode(Node* parent) {this->parentNode = parent;}
Node* getParentNode() {return this->parentNode;}
std::vector<Node> getChildNodes(){return this->childNodes;}
void addChildNode(Node* node);
void removeNode();
private:
std::vector<Node*> childNodes;
Node* parentNode = nullptr;
};
And a child inheriting from that class:
class Cube : public Node
{
public:
Cube();
};
Now I have another file which has a function that uses the child class:
#include "cube.h"
void addCubes(){
Cube mainCube;
for(int i = 0; i < 10; i++){
Cube c;
mainCube.addChildNode(c);
}
}
Problem is that mainCube doesn't see the addChildNode function which the parent has. What is the point of inheriting from another class if the parents functions aren't accessible from another place using the child class?
No, the parent classes public functions are callable from the child object.
However, the prototype of the function is
void Node::addChildNode(Node node);
So it's taking a Node object & not a Cube object.
So your compiler cannot find a function which takes a Cube object & hence the error.
The fix is to use a pointer to Node or reference to Node while declaring/defining the function.
So you function should be
void addChildNode(Node & node);
In which case, the Node object can be passed to the function & the compiler will find it.
Even better would be to have
// if you aren't looking to modify the passed object inside addChildNode
void addChildNode(const Node & node);
The following is fine & hence the function will work
Cube b;
Node &a = b;
or
Node * pn = &b;
The derived classes should be able to see the addChildNode function if you keep the signature of the function aligns. This is not a big issue. However, there are a few more "serious" issues with your code:
You need to make the base class' destructor virtual to avoid some undefined behaviors.
You have to design the ownership of nodes carefully. I guess you want the Node class to own and manage its children nodes. That means function addChildNode actually takes the ownership of the passed in node object, and it should also be deleted during destruction.
In function addCubes(), there is a loop that keeps calling addChildNode function but passes the local variable Cube c; which will be out of scope and destroyed after the loop. Thus, the parent object mainCube will holds pointers to already destroyed objects, and it will cause a crash.
After fixing all these issues, your code looks like this:
class Node
{
public:
Node() {};
virtual ~Node() {
for(auto n: childNodes) delete n;
};
void setParentNode(Node* parent) {this->parentNode = parent;}
Node* getParentNode() {return this->parentNode;}
std::vector<Node*> getChildNodes(){return this->childNodes;}
void addChildNode(Node* node) {
childNodes.push_back(node);
};
void removeNode();
private:
std::vector<Node*> childNodes;
Node* parentNode = nullptr;
};
class Cube : public Node
{
public:
Cube() {};
};
void addCubes(){
Cube mainCube;
for(int i = 0; i < 10; i++){
Cube *c = new Cube();
mainCube.addChildNode(c);
}
}
It is preferred to use smart pointers to manage memory, and the code is more elegant and easier to read, and it makes it harder to make mistakes :-).
#include <memory>
class Node
{
public:
Node() {};
virtual ~Node() {};
void setParentNode(Node* parent) {this->parentNode = parent;}
Node* getParentNode() {return this->parentNode;}
std::vector<std::shared_ptr<Node>>& getChildNodes(){return this->childNodes;}
void addChildNode(std::shared_ptr<Node> node) {
childNodes.push_back(std::move(node));
};
void removeNode();
private:
// childNodes own elements in it, they will be deleted automatically.
std::vector<std::shared_ptr<Node>> childNodes;
Node* parentNode = nullptr;
};
class Cube: public Node
{
public:
Cube() {};
};
void addCubes(){
Cube mainCube;
for(int i = 0; i < 10; i++){
auto c = std::make_unique<Cube>();
mainCube.addChildNode(std::move(c));
}
}
Assuming that you have shared the entire implementation of your code. You have not defined the body of the function addChildNode, similar to setParentNode etc. You need to do something like childNodes.push_back(node); inside that function.
Note: It is also necessary that you pass the input to addChildNode as shown in the answer by #user93353. Also, define childNodes as std::vector<Node *> in order to avoid object slicing.

How can I access member functions of STL classes inside derived classes that aren't in the base class? (detailed explanation in body)

Right now I have a base class, class Base{}, with two classes deriving from it, BFS{} and DFS{}. BFS has queue, and DFS has stack, so they both have a member called "nodes", but the type is their respective std::queue and std::stack. My search function takes in a pointer to base class as its parameter so that it can accept both derived classes, and runs the search by pushing and popping from the member classes inside the derived classes (as per the usual DFS BFS algorithms). The issue is, since I passed in my base class as the parameter, whenever I try to call push or pop on the member stack/queue called "nodes" from the derived classes, it always says that the push/pop cannot be done because there is no member inside the base class called "nodes". How am I supposed to make this work?
Also, this setup is a requirement of the assignment I am doing and I just can't figure out how this is supposed to work, any help is appreciated.
Thanks!
class Base {
public:
virtual void push(uint64_t roomID, float intensity, int distance) = 0;
virtual Node pop(void) = 0;
virtual int size(void) = 0;
};
class Breadth : public Base {
public:
std::queue<std::pair<uint64_t, int>> U;
void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
Node pop() { Node rr; rr.ID = U.front().first; rr.distance = U.front().second; U.pop(); return rr; }
int size() { return U.size(); }
};
class Depth : public Base {
public:
std::stack<std::pair<uint64_t, int>> U;
void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
UnexploredRoom pop() { U.pop(); }
int size() { U.size(); }
};
void robotSearch::searchLoop(Base* search, Discovered* D, uint64_t roomID)
{
Node room;
room.ID = roomID;
room.distance = 0;
search->U.push(room); //problem here, compiler wont let me push U
...
}
To implement custom behaviour through a pointer to a base class, you need to use virtual functions. Another approach would be to use generic code with templates.
Example:
class Base {
public:
virtual ~Base() {}
virtual void push(int i) = 0;
virtual int pop() = 0;
};
class DFS : public Base{
public:
virtual void push(int i) override { /*...*/ }
virtual int pop() override { /*...*/ return {}; }
};
class BFS : public Base {
public:
virtual void push(int i) override { /*...*/ }
virtual int pop() override { /*...*/ return {}; }
};
Right now, you have some virtual methods push and pop, but for some reason, you don't use them and instead try to access a member of the derived classes instead. You seem to have copied code from the answer by Ayjay but not applied it correctly.
That member U should really not be exposed like this, that is, it should be private, and you should use your class methods to manipulate it.
Therefore, you wouldn't write
search->U.push(room);
even if it was legal here (which it isn't, as the base class does not have anything named like that).
Instead, you go with
search->push(room);
Note that I omitted the other arguments that this takes, of course you also have to provide values for your intensity and distance arguments.
Doing so will call the appropriate method, that is either Breadth::push or Depth::push, which then will access the corresponding member of the respective class.
By the way, for reasons of control, you should use the override keyword as Ayjay did, and also, you should give a member a more descriptive name that U.

Can you set pointer to derived class after you set some values in the base class?

I am new to c++ (I am using visual studio 2013) and I started experimenting with classes and inheritance. So I came up with a question which I can not find any anwser. Lets say we have this class:
#include <iostream>
using namespace std;
class base{
protected:
int var;
public:
void setvalue(int);
virtual void print();
};
class first:public base{
public:
void print();
};
class second: public base{
public:
void print();
};
Is there a way I can declare in my main() a pointer to base, set the value and after that choose if it is a first or second class? Ex:
int main(){
base *ptr = new base;
ptr->setvalue(1);
/* Here I choose if base is pointing to First or Second class*/
ptr->print(); // use the correct member, based on which class I choosed
return 0;}
Is this somehow possible? (As I said I am new to c++ so in case you have any questions, feel free to ask!)
Thanks!
Since it's not possible, the only thing that comes to mind is that you solve your problem in another way, perhaps using some well common design pattern.
In this case, given the little information you gave, Factory pattern seems appropriate.
#include <iostream>
using namespace std;
class base {
protected:
int var;
public:
void setvalue(int);
virtual void print();
static base* makeObject(int);
};
class first : public base {
public:
void print();
};
class second : public base {
public:
void print();
};
base* base::makeObject(int param) {
base* ret = NULL;
if(/* some condition based on params */) {
ret = new first();
ret->setvalue(0);
} else if(/* some other condition */) {
ret = new second();
ret->setvalue(1);
}
return ret;
}
int main() {
base *ptr = base::makeObject(...);
base->print(); // use the correct member, based on which class I choosed
return 0;
}
The type of an object is fixed at construction and can never be changed. So the direct answer to your question is "no".
But within that framework you have a lot of power. For example, you could separate your three classes out into four: three that do just do printing (BasePrinter, DerivedPrinter1, DerivedPrinter2) and other that just holds the value and doesn't have any virtual methods. Your BasePrinter class could get passed a ValueHolder object (by const reference) every time you call the print() method. Alternatively, each ValueHolder could have a pointer to BasePrinter object and pass in all the necessary data each time, with a little (non-virtual) print() method to do all this forwarding.
Not directly. When you create an object, you need to specify its full type so that C++ knows how to correctly lay out memory for you.
If you actually need to change it later, you can always create a new class (of the correct derived type) and use the original base class to initialize it, then delete the original. This might be slightly slower than the method you were proposing (depending on the final complexity of the class), but it would get the job done.
Since you are using inheritance , it is best practice to define virtual destructor in your base class. It will take care proper clean up when you define complicated class.
int main(){
base *ptr = new base;
base->setvalue(1);
/* Here I choose if base is pointing to First or Second class*/
base->print(); // use the correct member, based on which class I choosed
return 0;}
What you are trying to do is not possible. You have to change your program as follows to avoid compilation error.
base *ptr = new base;
ptr->setvalue(1);
ptr->print();
delete ptr;
return 0;
Because you base pointer ptr always have the dynamic type of class base. this code always invoke base::print function
If you define ptr as follows, you can utilize the polymorphism.
base * ptr = new first;
ptr->setvalue(1);
ptr-> print()
delete ptr
Here ptr has a dynamic type of class first and it will call function first::print()
You have to choose type at the creation of the object:
int main()
{
base *ptr = new first; // here.
ptr->setvalue(1);
ptr->print(); // use first::print.
delete ptr;
}

C++ class that can hold one of a set of classes that all inherit from a common class

What are the ways in C++ to handle a class that has ownership of an instance of another class, where that instance could potentially be of a number of classes all of which inherit from a common class?
Example:
class Item { //the common ancestor, which is never used directly
public:
int size;
}
class ItemWidget: public Item { //possible class 1
public:
int height;
int width;
}
class ItemText: public Item { //possible class 2
std::string text;
}
Let's say there is also a class Container, each of which contains a single Item, and the only time anyone is ever interested in an Item is when they are getting it out of the Container. Let's also say Items are only created at the same time the Container is created, for the purpose of putting them in the Container.
What are the different ways to structure this? We could make a pointer in Container for the contained Item, and then pass arguments to the constructor of Container for what sort of Item to call new on, and this will stick the Items all in the heap. Is there a way to store the Item in the stack with the Container, and would this have any advantages?
Does it make a difference if the Container and Items are immutable, and we know everything about them at the moment of creation, and will never change them?
A correct solution looks like:
class Container {
public:
/* ctor, accessors */
private:
std::unique_ptr<Item> item;
};
If you have an old compiler, you can use std::auto_ptr instead.
The smart pointer ensures strict ownership of the item by the container. (You could as well make it a plain pointer and roll up your own destructor/assignment op/copy ctor/move ctor/ move assignment op/ etc, but unique_ptr has it all already done, so...)
Why do you need to use a pointer here, not just a plain composition?
Because if you compose, then you must know the exact class which is going to be composed. You can't introduce polymorphism. Also the size of all Container objects must be the same, and the size of Item's derived classes may vary.
And if you desperately need to compose?
Then you need as many variants of Container as there are the items stored, since every such Container will be of different size, so it's a different class. Your best shot is:
struct IContainer {
virtual Item& getItem() = 0;
};
template<typename ItemType>
struct Container : IContainer {
virtual Item& getItem() {
return m_item;
}
private:
ItemType m_item;
};
OK, crazy idea. Don't use this:
class AutoContainer
{
char buf[CRAZY_VALUE];
Base * p;
public:
template <typename T> AutoContainer(const T & x)
: p(::new (buf) T(x))
{
static_assert(std::is_base_of<Base, T>::value, "Invalid use of AutoContainer");
static_assert(sizeof(T) <= CRAZY_VAL, "Not enough memory for derived class.");
#ifdef __GNUC__
static_assert(__has_virtual_destructor(Base), "Base must have virtual destructor!");
#endif
}
~AutoContainer() { p->~Base(); }
Base & get() { return *p; }
const Base & get() const { return *p; }
};
The container requires no dynamic allocation itself, you must only ensure that CRAZY_VALUE is big enough to hold any derived class.
the example code below compiles and shows how to do something similar to what you want to do. this is what in java would be called interfaces. see that you need at least some similarity in the classes (a common function name in this case). The virtual keyword means that all subclasses need to implement this function and whenever that function is called the function of the real class is actually called.
whether the classes are const or not doesn't harm here. but in general you should be as const correct as possible. because the compiler can generate better code if it knows what will not be changed.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class outputter {
public:
virtual void print() = 0;
};
class foo : public outputter {
public:
virtual void print() { std::cout << "foo\n"; }
};
class bar : public outputter {
public:
virtual void print() { std::cout << "bar\n"; }
};
int main(){
std::vector<outputter *> vec;
foo *f = new foo;
vec.push_back(f);
bar *b = new bar ;
vec.push_back(b);
for ( std::vector<outputter *>::iterator i =
vec.begin(); i != vec.end(); ++i )
{
(*i)->print();
}
return 0;
}
Output:
foo
bar
Hold a pointer (preferably a smart one) in the container class, and call a pure virtual clone() member function on the Item class that is implemented by the derived classes when you need to copy. You can do this in a completely generic way, thus:
class Item {
// ...
private:
virtual Item* clone() const = 0;
friend Container; // Or make clone() public.
};
template <class I>
class ItemCloneMixin : public Item {
private:
I* clone() const { return new I(static_cast<const I&>(*this); }
};
class ItemWidget : public ItemCloneMixin<ItemWidget> { /* ... */ };
class ItemText : public ItemCloneMixin<ItemText> { /* ... */ };
Regarding stack storage, you can use an overloaded new that calls alloca(), but do so at your peril. It will only work if the compiler inlines your special new operator, which you can't force it to do (except with non-portable compiler pragmas). My advice is that it just isn't worth the aggravation; runtime polymorphism belongs on the heap.

c++ handling derived class that's self referencing

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.