A friend template class of another template class with the same types

Jun 22, 2010 at 8:55pm
Hello folks!

First I'd like to explain myself saying that I know there are already a lot of threads discussing this topic, but I found myself totally lost among them. Each gave me different answer and none was correct.
Nevertheless, if there is already a good answer to my question, please post a link to it.

I'll try to express my problem clearly.

In my programme I'm creating two template classes. A good example can be a BST tree:

1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
class BSTNode {
  T value;
  T *parent, *left, *right;
  BSTNode<T>();
};

template <class T>
class BSTTree {
  BSTNode<T> root;
  //some useful methods here
};


A little explanation
I do want to have all fields (variables) in BSTNode private and I don't want any public methods in it.
This is because I want BSTTree to be the only class permitted to make any use of BSTNode. This is also the reason why the default constructor in BSTNode is private.

Now, to achieve my goal I want to declare BSTTree as a friend class of BSTNode. I can do it this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class T>
class BSTNode {
  T value;
  T *parent, *left, *right;
  BSTNode<T>();
  template <class U> friend class BSTTree;
};

template <class T>
class BSTTree {
  BSTNode<T> root;
  //some useful methods here
};


What my problem is
I want to make my code more secure. Because

<class U>

means any type it is possible, for instance, for a

BSTTree<std::string>

to access fields of a

BSTNode<int>

This is the type of situation I want to prevent. I want each instance of BSTNode class to be accessible only by an instance of BSTTree class with the same T types.

Unfortunately, I can't do the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//CAUTION!
//faulty code below!

template <class T>
class BSTNode {
  T value;
  T *parent, *left, *right;
  BSTNode<T>();
//the line below produces an error
//the only change is substituting 'U' for 'T'
  template <class T> friend class BSTTree;
};

template <class T>
class BSTTree {
  BSTNode<T> root;
  //some useful methods here
};


G++ gives me an error:

BSTree.cpp:11: error: declaration of `class T'
BSTree.cpp:4: error:  shadows template parm `class T'


Finally, the question
What is the proper way of solving this problem?
Is there a proper friend class declaration to use?
If no, what is another way of doing this?

Cheers,
Paul

PS. I know that I can simply be careful to use the code in the way I want. But to feel safe I want the compiler to take care of it.
Last edited on Jun 22, 2010 at 8:56pm
Jun 22, 2010 at 8:58pm
Declare BSTNode<> in the private section of BSTTree<>.

Then nobody can use it except BSTTree<>.
Jun 22, 2010 at 9:08pm
I also recommend what jsmith said, but changing the faulty line to simply
friend class BSTTree<T>;
should solve your problem too.
Jun 22, 2010 at 9:08pm
jsmith, thanks for your fast answer!

But could you please tell me what this change means?
And does it prevent the situation I mentioned above? (having BSTTree<std::string> to use BSTNode<int>)
Jun 22, 2010 at 9:13pm
R0mai, when I do the change g++ says:

BSTree.cpp:11: error: `BSTTree' is not a template


I've tried that before creating this post.
Jun 22, 2010 at 9:14pm
1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
class BSTTree 
{
   private:
       struct BSTNode
       {
             // Other stuff here
             T data;
       };

   // Rest of BSTTree here
};


Only member functions of BSTTree<T> can access BSTNode since the type is private to it.
And BSTTree<int> will contain a struct containing "int data" and BSTTree<std::string> will
have a struct containing "std::string data". No chance of what you are asking.
Jun 22, 2010 at 9:20pm
jsmith, excellent solution!

I did't think of that. An idea of nesting one class in the other drifted in my mind, but it's impossible to do in C++. And this made me forget of declaring a struct in a class.
Now I have all I need to proceed with my programme.

Thanks a million!
Paul
Jun 22, 2010 at 9:27pm
You have to forward declare.
Put this before BSTNode.
template<class T> BSTTree;
Jun 22, 2010 at 9:56pm
R0mai, you're totally right except for a little spelling mistake:
template <class T> class BSTTree;

Now the problem is solved in two ways.

Thank you two guys!
Jun 22, 2010 at 10:05pm
Final conclusion for someone (possibly) reading this in future

The 'FAULTY CODE' in the first post isn't totally faulty. The only thing to change is to declare BSTTree before BSTNode definition.

The proper and working code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T> class BSTTree;
template <class T>
class BSTNode {
  T value;
  T *parent, *left, *right;
  BSTNode<T>();
  friend class BSTTree <T>;
};

template <class T>
class BSTTree {
  BSTNode<T> root;
  //some useful methods here
};


It solves the problem.


The solution suggested by jsmith is also worth mentioning, and I think that it's even better than my first idea was.
Proper code:

1
2
3
4
5
6
7
8
9
10
template <class T>
class BSTTree {
  struct BSTNode {
    T value;
    T *parent, *left, *right;
  };

  BSTNode root;
  //some useful methods here
};


This code is more compact and (more importantly) sticks BSTNode to BSTTree.

I'm now marking this topic as solved.
Jun 22, 2010 at 10:20pm
Two points of clarification:

1) classes can be nested in classes in C++.
2) since it is the intent to disallow users from using BSTNode, it is best made a private type in the class rather
than polluting the (global) namespace with a useless symbol.

Jun 24, 2010 at 8:45am
To jsmith,

1) Wow, so it means I was wrong all the time. I was just sure I read somewhere that I can't have nested classes. Probably got it wrong.

2) Yes, you're right about that.

Thanks!
Topic archived. No new replies allowed.