I've just discovered some very odd behavior in my program. I have a tree where every Node is a subclass of Node. I recursively calculate a bounding box by traversing the tree until I reach the unit primitives (i.e. a Cube : Node) at the leaf nodes.
The recursive function getBoundingBox() is declared as virtual and correctly traverses the tree. Leaf nodes override the function and return a unit cube.
However, when I trace the program it appears that the override has no effect on the recursive function getBoundingBox(), even though it works just fine for another function like getName().
Example:
class Node;
typedef shared_ptr<Node> node_ptr;
class Node
{
protected:
vector<node_ptr> mChildren;
public:
virtual string getName() { return "Node";}
virtual BoundingBox getBoundingBox()
{
//Merge Bounding Boxes of Children
BoundingBox bb = BoundingBox();
//For each child
for(vector<node_ptr>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
string name = (*it)->getName();//Correctly returns Node or Cube depending on type of (*it)
bb = BoundingBox::Merge(bb, (*it)->getBoundingBox());//Always calls Node::getBoundingBox(); regardless of type
}
return bb;
}
};
class Cube : public Node
{
public:
virtual string getName() { return "Cube";}
virtual BoundingBox getBoundingBox()
{
return BoundingBox::CreateUnitCube();
}
};
Is there some sort of caveat about recursive polymorphism in c++ that I'm missing?
I think your inheritance structure is muddled up. It makes more sense to have a base class Node which may be abstract
class BaseNode {
public:
virtual BoundingBox getBoundingBox() const = 0;
};
and then define the different types of nodes
using node_ptr = std::shared_ptr<BaseNode>;
class Node : public BaseNode
{
std::vector<node_ptr> mChildren;
public:
BoundingBox getBoundingBox() const noexcept
{
BoundingBox bb;
for(auto pc:mChildren)
bb.merge(pc->getBoundingBox());
return bb;
}
};
class Cube : public BaseNode
{
public:
BoundingBox getBoundingBox() const noexcept
{ return BoundingBox::CreateUnitCube(); }
};
Cube isn't a Node as you didn't use public inheritance.
I'm not sure how your actual code even compiles, but try to change it to:
class Cube : public Node
Related
I have a tree structure, created from derived classes from Node. Each Node has pointer to it's parent and a virtual function Symbols(). Here is simplified example:
struct Node {
Node* parent;
virtual const SymbolTable& Symbols() { return parent->Symbols(); }
}
struct A : public Node {
}
struct B : public Node {
SymbolTable symbols;
const SymbolTable& Symbols() override { return symbols; }
}
So in this tree structure, A nodes doesn't have SymbolTable and B nodes do. All I need to do is for the Symbols() method return first SymbolTable above current node, but it seems that the overridden method in B is never getting called.
I just tried this and polymorphism-wise it works on my end.
This is the code I ran:
struct SymbolTable {
int sym = 42;
};
struct Node {
Node* parent{ nullptr };
virtual const SymbolTable& Symbols() { return parent->Symbols(); }
};
struct A : public Node {
};
struct B : public Node {
SymbolTable symbols;
const SymbolTable& Symbols() override { return symbols; }
};
int main()
{
B parent;
A child;
child.parent = &parent;
std::cout << child.Symbols().sym << std::endl;
return 0;
}
The output of this is
42
as expected.
Therefore, the method of B is called.
However, be advised that if you have a Node of type A that has no parent the program will crash, because an invalid pointer is accessed (I initialized it to nullptr in this example, and so should you). In this example that would mean changing the type of parent to A. In that case the program will crash with an access violation (because the parent of parent is a null pointer).
So I am creating a Huffman tree, and I am having a hard time overriding a function, and I believe that it is due to a covariance issue. Here is the hierarchy that I am having a hard time with in my code:
class TreeInterface {
public:
TreeInterface() {}
virtual ~TreeInterface() {}
virtual NodeInterface * getRootNode() const = 0;
};
class Tree : TreeInterface
{
public:
Tree()
{}
virtual ~Tree()
{}
Node* getRootNode()
{
return treeRoot;
}
private:
Node* treeRoot;
};
Those work just fine, but its the next block that has issues.
class HuffmanInterface{
public:
HuffmanInterface() {}
virtual ~HuffmanInterface() {}
virtual bool createTree(string filename) = 0;
virtual string encodeMessage(string toEncode) = 0;
virtual TreeInterface * getTree() = 0;
virtual map<char, string> getEncodings() = 0;
};
class Huffman : HuffmanInterface{
public:
Huffman() {}
~Huffman() {}
bool Huffman::createTree(string filename){ }
string Huffman::encodeMessage(string toEncode){ }
string Huffman::decodeMessage(string toDecode){ }
Tree* Huffman::getTree(){ }
map<char, string> Huffman::getEncodings(){ }
So the problem is apparently in the getTree() function, giving the following error
invalid covariant return type for ‘virtual Tree* Huffman::getTree()’:
Tree * getTree();
but as far as I know, Tree* should be a valid covariant of TreeInterface*. replacing Tree* with TreeInterface* makes the program compile, but it's not what I need in my actual program. Any help is greatly appreciated!
class Tree : TreeInterface { ... };
is equivalent to
class Tree : private TreeInterface { ... };
You need to make the inheritance public.
class Tree : public TreeInterface { ... };
I have this tree with different types of nodes that I need to do a deep copy on. The hierarchy looks something like this:
class AllNodes
{
//this is a purely virtual base class
};
class TreeNode : public AllNodes
{
AllNodes *rChild, *lChild;
};
class LeefNode : public AllNodes
{
int value;
};
The problem is that when I want to do a deep copy of the entire tree, I don't know what nodes will have children and what nodes will have values. I've tried this, but it wont work (for obvious reasons):
void AllNodes::deepCopy(AllNodes* &copied, AllNodes* o)
{
if(o->rChild == nullptr)
copied->rChild = nullptr;
else
{
copied->rChild = o->rChild;
deepCopy(copied->rchild, o->rChild);
}
if(o->lChild == nullptr)
copied->lChild = nullptr;
else
{
copied->lChild = o->lChild;
deepCopy(copied->lChild, o->lChild);
}
}
Does anyone have some ideas of how to accomplish this?
Create a virtual method and implement it in TreeNode and LeafNode.
class AllNodes
{
//this is a purely virtual base class
virtual AllNodes* copy() const = 0;
};
class TreeNode : public AllNodes
{
AllNodes* rChild, lChild;
virtual AllNodes* copy() const {
TreeNode *n = new TreeNode;
n->rChild = rChild->copy();
n->lChild = lChild->copy();
return n;
}
};
class LeafNode : public AllNodes
{
int value;
virtual AllNodes* copy() const {
LeafNode *n = new LeafNode;
n->value = value;
return n;
}
};
(Just a draft)
This is polymorphic behavior (creating a deep copy, based on the concrete type of the object). As such, it should be implemented in a virtual function, accross the entire nodes hierarchy.
The function to perform the deep copy is usually called clone:
class AllNodes
{
//this is a purely virtual base class
public:
virtual AllNodes* clone() = 0;
};
class TreeNode : public AllNodes
{
AllNodes *rChild, *lChild; // you skipped declaring lChild as a pointer
public:
virtual AllNodes* clone() override // recursive implementation for child nodes
{
return new TreeNode{
rChild ? rChild->clone() : nullptr,
lChild ? lChild->clone() : nullptr }; // assume existence of this
// constructor
}
};
class LeafNode : public AllNodes
{
int value;
public:
virtual AllNodes* clone() override
{
return new LeafNode{ value }; // assume existence of this constructor
}
};
Client code (deep copy of the entire tree):
AllNodes *original; // filled in elsewhere
AllNodes *deepCopy = original->clone();
I have an abstract class Node which contains a pure virtual method stub matches, requiring another instance of a Node (i.e. instance of something that subclasses Node) as a parameter.
class Node; // forward declaration
class Node {
public:
Node() : parentNode(this) {}
virtual ~Node() {}
Node* parentNode;
virtual bool matches(const Node& node) const = 0;
};
How can I implement matches in a subclass such that the parameter can be of the subclasses type as opposed to Node?
E.g. I want something like the following to register as the implemented version of the contract from Node, so that I can access NodeImpl specific properties as part of the function which I would otherwise be unable to do:
class NodeImpl : public Node {
private:
int foo;
...
};
...
bool NodeImpl::matches(const NodeImpl& n) const {
return this->foo == n.foo;
}
(I did have a try using templates to achieve this sort of effect, but I wasn't sure that I was doing it quite right. I found myself propagating the templates all over my code and encountering a myriad errors as such, and was hoping to get an idea of what the right method for this exactly is before I waste yet more time on what might well be also the wrong way of doing things.)
What I tried was:
template <class T>
class Node;
template <class T>
class Node {
public:
Node() : parentNode(this) {}
virtual ~Node() {}
Node* parentNode;
virtual bool matches(const T& node) const = 0;
};
So that I could call matches generically in a template function like so:
template <class T>
void pathComp(Node<T>& currNode, Node<T>& rootNode) {
Node<T> *node = &currNode;
while (node->matches(rootNode)) {
...
}
}
I couldn't quite get this method to work, plus I didn't like how I seemingly had to have class NodeImpl : public Node<NodeImpl> as my inheritance, something about that didn't seem quite right. Any advice as to whether I was on the right lines or not would be great!
You can't really do that in general, because it wouldn't be type-safe. For example:
struct Node { virtual bool matches(const Node &) const = 0; }
struct NodeA : Node { virtual bool matches(const NodeA &) const; };
struct NodeB : Node { virtual bool matches(const NodeB &) const; };
NodeA a; // compiler doesn't allow, but if it did...
NodeB b;
Node &c = a;
c.matches(b); // oops!
The way you are talking about implementing it, there would be an assumption that b was the same type as a, but there is no way for the compiler to verify that assumption in general, so it isn't going to allow it.
However, if you are using two nodes of the same type, you can always have the matches() function just not be virtual:
struct Node { }
struct NodeA : Node { bool matches(const NodeA &) const; };
NodeA a1;
NodeA a2;
a1.matches(a2); // fine
You should honor the superclass' contract signature. Then if you need
to access sub-class properties, just cast to the sub-class, as needed.
I need to store a polymorphic object (let's say Polygon) inside another object (let's say Simulation). At the same time I want to keep encapsulation of Simulation.
class Polygon {
public:
virtual double area() { return 0; }
};
class Square : public Polygon {
public:
Square(double edge) : edge_(edge) {}
virtual double area() { return edge_*edge_; }
private:
double edge_;
};
class Simulation {
public:
Simulation(Polygon& polygon) { polygon_ = &polygon; }
Polygon* polygon() { return polygon_; }
private:
Polygon* polygon_;
};
int main (int argc, const char * argv[]) {
Square square(2.0);
Simulation sim(square);
std::cout<<sim.polygon()->area()<<"\n";
return 0;
}
This works perfectly fine! However, it violates encapsulation of Simulation, in fact, if from the main I go and change square it will also change inside Simulation.
I was thinking of modifying the constructor of Simulation using the copy constructor as:
Simulation(Polygon& polygon) { polygon_ = new Polygon(polygon); }
but this will mean that I don't have polymorphism...
There is obviously something I am missing here... CHEERS!
Add a clone function to Polygon (and a virtual destructor!). It is a good idea to ensure that Polygon is abstract so make sure at least one function is pure virtual.
Your Simulation class will require a copy constructor, destructor and assignment operator.
Note that the Square clone function can return a Square* even though the super class returns a Polygon* because it is covariant. Some older compilers may not support this, in which case return a Polygon*.
class Polygon {
public:
virtual ~Polygon() = 0;
virtual Polygon* clone() const = 0;
virtual double area() { return 0; }
};
inline Polygon::~Polygon() {}
class Square : public Polygon {
public:
Square(double edge) : edge_(edge) {}
virtual Square* clone() const { return new Square(*this); }
virtual double area() { return edge_*edge_; }
private:
double edge_;
};
class Simulation {
public:
Simulation(Polygon const& polygon)
: polygon_(polygon.clone())
{}
Simulation(Simulation const& rhs)
: polygon_(rhs.polygon_->clone())
{}
Simulation& operator=(Simulation const& rhs)
{
if (this != &rhs) {
delete polygon_;
polygon_ = rhs.polygon_->clone();
}
return *this;
}
~Simulation() {
delete polygon_;
}
Polygon* polygon() { return polygon_; }
private:
Polygon* polygon_;
};
If Simulation contains Polygon then it means that it is meant to do something with it. If you need to access the polygon directly from the 'outside', you have either missed the design somewhere, or if not, you can use observer pattern and have polygon notify the simulation if something about it changes.
So, either:
outside -> polygon -> callback -> simulation
or
outside -> simulation -> polygon
So you want to make sure that there's no way for outside code to alter the inner polygon of simulation, but yet allow any subclass to be used inside it? I.e. make sure that there are no references outside of simulation to the object passed by ref in the c'tor?
You could think of an abstract copy method to accomplish that: (don't forget to delete in simulation destructor)
class Polygon {
public:
virtual Polygon *copy() = 0;
//..
};
class Square : public Polygon {
public:
virtual Polygon *copy() { return new Square(_edge); }
//...
}
class Simulation {
public:
Simulation(const Polygon &p) : poly(p.copy()) {}
};
If you want to copy a polymorphic object, this can be done with a clone method.
class Polygon
{
...
virtual Polygon* clone() const = 0;
};
class Square: public Polygon
{
...
virtual Square* clone() const { return new Square(*this); }
};
However, in the example it seems a bit pointless that the Simulation neither does anything with the polygon itself nor do you want to hand it out for other code to use.
That's just how C++ works. If you write a wrapper for an object (PIMPL) you have to implement its full interface. The functions going to be very small just passing the calls to the actual implementation but you have to write them. Then you can alter the behaviour, add logging, or whatever you need...
You just need to decide if the polygon is inside or outside of simulation. If it's supposed to be outside of it, then you have reference constructor parameter . If it's inside, you'll need the following code:
class Simulation {
public:
Simulation() : poly(2.0) { }
Polygon *polygon() { return &poly; }
private:
Square poly;
};
Now, the polymorphism aspect you can easily do like this:
class Simulation {
public:
Simulation() : poly(2.0), poly2(3.0) { }
Polygon *polygon(int i)
{
switch(i) {
case 0: return &poly;
case 1: return &poly2;
}
return 0;
}
private:
Square poly;
Cylinder poly2;
};
And once you get tired to adding new data members, here's another trick which will fix some cases:
class Simulation {
public:
Simulation() : poly(2.0) { }
Polygon *polygon(float x)
{
poly.edge_ = x;
return &poly;
}
private:
Square poly;
};
Edit: Note that the order of classes in header file needs to be carefully considered.