views:

142

answers:

4

Hey,

I'm experiencing some problems with breaking my code to reusable parts using templates and inheritance. I'd like to achieve that my tree class and avltree class use the same node class and that avltree class inherits some methods from the tree class and adds some specific ones. So I came up with the code below. Compiler throws an error in tree.h as marked below and I don't really know how to overcome this. Any help appreciated! :)

node.h:

#ifndef NODE_H
#define NODE_H
#include "tree.h"

template <class T>
class node
{
T data;
    ...

node()
    ... 

  friend class tree<T>;
};

#endif

tree.h

#ifndef DREVO_H
#define DREVO_H

#include "node.h"

template <class T>
class tree
{
public: //signatures
    tree();
...

    void insert(const T&);
private:
    node<T> *root; //missing type specifier - int assumed. Note: C++ does not support default-int


};
//implementations

#endif

avl.h

#ifndef AVL_H
#define AVL_H

#include "tree.h"
#include "node.h"

template <class T>
class avl: public tree<T>
{
public: //specific
    int findMin() const;
...

protected:
    void rotateLeft(node<T> *)const;
private:
    node<T> *root;

};

#endif

avl.cpp (I tried separating headers from implementation, it worked before I started to combine avl code with tree code)

#include "drevo"
#include "avl.h"
#include "vozlisce.h"

template class avl<int>; //I know that only avl with int can be used like this, but currently this is doesn't matter :)
//implementations
...
+8  A: 

Both tree.h and node.h try to include each other, the include guards will prevent one of them from seeing the other.

Instead of #include "tree.h" try forward declaring tree like:

template <class T>
class tree;

in node.h

EDIT: As sbi suggested in a comment, it makes more sense to forward declare tree in node.h than the other way around, since it's about granting tree access to node through a friend declaration.

Andreas Brinck
I would think it would make more sense to not to `#include "tree.h"` in `"node.h"` than the other way around. It's hard to imagine how to implement a tree without the nodes, after all, while for the `friend` declaration a forward declaration of `tree` should suffice.
sbi
@sbi You're right of course
Andreas Brinck
Recursive includes are just so funny... do you know of any preprocessor that warns about those beasts ? I mean one could write `#ifdef HEADER_GUARD \n #error "HEADER_GUARD defined" \n #else` instead of `#ifndef` but it's already so much clutter...
Matthieu M.
@Matthieu M. Maybe a macro... ;)
Andreas Brinck
@Matthieu: that would just cause spurious errors throughout your code. The reason we have header guards is that we often *do* include the same header multiple times in a compilation, without any recursion. If A and B both include C, and D includes A and B, then C gets included twice, and there's no recursion, no cycles in the include graph. Your suggestion would generate an #error when the code is perfectly valid, and extremely commonplace.
jalf
Yes, that's why I talked about warnings before, should have written `#warning`. Also even though it's perfectly legal, it is nonetheless quite inefficient. One of our major gains in compile time was realized by dusting off unnecessary includes (and I don't mean by forward declaring, just not reincluding a file that's already included by another included file). It's a bit more friable, but we're talking of a few dozens thousands headers there so look-up was slow. Curiously we never went the precompiled header road.
Matthieu M.
+2  A: 

Don't #include "tree.h" in "node.h".

Also, you've declared root in both the tree and avl classes. Qualify tree::root as protected and remove avl::root.

Marcelo Cantos
A: 

The problem is because of the circular dependency of header files between tree.h and node.h . Since node.h includes tree.h, while compiling the tree class, compiler doesn't know what is the type of node. Since you are using it just for declaring a friend there is no need to include the header file tree.h in node.h

Naveen
+1  A: 

Your problem is that tree.h includes node.h and vice versa. I would not have thought it is necessary (or makes much sense) for the node to have to know about the tree or to grant it friendship, so I'd remove that.

anon