Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Friends in inheritance (http://www.programmingforums.org/showthread.php?t=14918)

Lakrids Jan 11th, 2008 4:56 AM

Friends in inheritance
 
Hello,

There is a rather annoying problem in my code, and I just can't get to the bottom of it. I have a class, A, and another one, B, which inherits from A. Now, A has a friend class, C, which is declared inside it.

Whenever I want to use C's public constructor from within a method of B, I get errors like "expected type-specifier", and "expected ';'".

I know friends are not inherited, so I made C a friend of B, too. Which changes absolutely nothing. Always the same errors. What am I doing wrong? If I call C's constructor like : A::C(...), or simply C(...), I get the same errors.

Have any ideas?

Thanks

grumpy Jan 11th, 2008 5:29 AM

Re: Friends in inheritance
 
My guess, not having seen code that illustrates the problem, is that you've left out a semi-colon or a closing brace somewhere in code before where the error is reported.

Or - less likely - you're working with template classes, for which the rules are slightly different, and you've left out a "typename" keyword at a point where you need it.

Lakrids Jan 11th, 2008 5:45 AM

Re: Friends in inheritance
 
Nice guess, I AM working with template classes. OK, here's the simplified code to illustrate what is happening :

:

  1. template <typename T> class A {
  2.     protected :
  3.         class C;
  4.     public :
  5.         ...code...
  6. };
  7.  
  8. template <typename T> class A<T>::C {
  9.     friend class A;
  10.     public:
  11.         C(...params...);
  12. };
  13.  
  14.  
  15. template <typename T> class B : public A<T> {
  16.     int var;
  17.     method1(...);
  18.     ...
  19. };


Now, here's the problem :

:

  1. template <typename T> B<T>::method1(...) {
  2.     this->var = C(...);
  3. }


generates errors.

So does :

:

  1. template <typename T> B<T>::method1(...) {
  2.     this->var = A<T>::C(...);
  3. }


EVEN IF, before declaring the class A, I declare B like so :

:

  1. template <typename T> class B;


and put, in class C :

:

  1. friend class B<T>;


When using method1, I get the same errors.

What should I do? How can B access C's constructor?

grumpy Jan 11th, 2008 6:33 AM

Re: Friends in inheritance
 
It is usually better if you provide a SMALL but COMPLETE code sample that illustrates your problem. By paraphrasing, as you've done, you force people to guess at your problem because you may have left out key details.

My primary guess is that you've encountered one of the obscure limitations with templates in the current C++ standard -- fixing it is on the list of proposals for a future version of the standard. To make use of A<T>::C within a member function of B<T> you need to implement the member function inline (i.e. within the declaration of B<T>). For example;
:

template <typename T> class B : public A<T> {
public:
  int var;
  void method() {A<T>::C  x;  var = x;};    // assumes A<T>::C can be implicitly converted to int
};

The second problem I can see is this snippet of yours which (even ignoring the fact it is not within the class declaration);
:

template <typename T> B<T>::method1(...) {
      this->var = A<T>::C(...);
 }

can actually look like a function call to the compiler (a call of a function that doesn't exist, hence a compiler error). Since you've paraphrased your code (rather than providing actual code) I can't exclude this possibility.

But, in any event, the problem has nothing to do with friendship (friendship affects accessibility, not the sort of thing you're seeing).

Without an actual code sample that illustrates your problem, I can't/won't guess further.

Lakrids Jan 11th, 2008 7:07 AM

Re: Friends in inheritance
 
First of all, thank you for your help.

Second, here is the actual code :

:

  1. // Class "A"
  2. template <typename T> class LinkedList {
  3.         protected:
  4.                 class Element;
  5.                 Element *headOfList;
  6.         public:
  7.                 <constructor, destructor, and other methods>
  8. };
  9.  
  10.  
  11. // Class "C"
  12. template <typename T> class LinkedList<T>::Element {
  13.         protected:
  14.             friend class LinkedList;
  15.             int info;
  16.         public:
  17.             Element (int info=0, const LinkedList& next); // constructor
  18. };
  19.  
  20.  
  21. // Class "B"
  22. template <typename T> class DerivedList : public LinkedList<T> {
  23.  
  24.         public:
  25.                 ...
  26.                 // The actual method I was talking about is a "conversion constructor"
  27.                 explicit DerivedList(const LinkedList<T>& );
  28.                 ...
  29. };
  30.  
  31. // The actual definition of the method :
  32. template <typename T> DerivedList<T>::DerivedList(const LinkedList<T>& list) {
  33.         this->headOfList = new Element(*list.headOfList);
  34. }


generates the following errors at 'new Element" :
error : expected type-specifier before 'Element'

And if I write :

:

  1. this->headOfList = new LinkedList<T>::Element(*list.headOfList);


i get:
error : expected type-specifier

So, my idea was to put

:

  1. friend class DerivedList<T>


inside the class Element, and declaring DerivedList before LinkedList like so :

:

  1. template <typename T> class DerivedList;


and the compiler gives the very same errors as before.

What do you think?

grumpy Jan 11th, 2008 5:42 PM

Re: Friends in inheritance
 
Yep; you're running into the issue of dependant template types (instantiation of DerivedList template relies on instantiation of the LinkedList template, .... etc and the compiler is allowed to defer instantiation of any of those templates until it is too late).

In your particular case, a workaround I suggest is providing a copy constructor for LinkedList<> with the same body as your current DerivedList<> copy constructor, and not explicitly implement the DerivedList copy constructor. (the compiler generated copy constructor for DerivedList would automatically invoke the inherited one).

Other than that, you need to inline ALL your definitions (no reliance on forward declaration of the Element class, no "out of line" implementation of copy constructors, etc). The philosophy is making sure that the compiler has access to all information it needs when .... eventually ... it finds it needs to instantiate templates.

Friend declarations are not a solution to the problem: they just influence what code is allowed to access something. If it was, you could just make everything public and the problem would go away.

More generically (C++ template issues aside) I'm failing to work out how your design makes sense for a linked list. Your LinkedList contains a pointer to an element, and presumably each element needs a pointer to the LinkedList that contains it. That circular dependancy does not make sense to me. Generally I would expect the nodes of a linked list (your Element) would contain data (the info member), and one or more pointers to other nodes. No need for a pointer back to the containing LinkedList.

Practically, I'd also use a std::list<> anyway, rather than rolling my own linked list template as well. I assume you're doing this for learning purposes.

Lakrids Jan 12th, 2008 4:42 AM

Re: Friends in inheritance
 
Thank you ever so much for these tips.

As for your remarks about the implementation of the list, I agree with you. This code is not mine, it is given by an educator, who wants us to further enhance it. I know there are many much simpler ways (and more clearer ways) to implement a linked list, the aim of this exercise was to make us familiar with friends in inheritance. But you are absolutely right : this code is not efficient at all, and moreover, it is very unclear.

Having said this, I thank you once more for outlining what should and should not be done when using template classes like this...so much I didn't know.

Jessehk Jan 12th, 2008 9:30 AM

Re: Friends in inheritance
 
I was playing around with writing data structures in C++ a while ago. I hope this is somewhat useful.

:

  1. #include <iostream>
  2.  
  3. template <typename T>
  4. class ListNode {
  5. private:
  6.     T data_;
  7.     ListNode<T> *next_;
  8. public:
  9.     explicit ListNode( const T &data, ListNode<T> *next=0 ) :
  10.         data_( data ),
  11.         next_( next ) {}
  12.  
  13.     const T &data() const { return data_; }
  14.     void setData( const T &newData ) { data_ = newData; }
  15.  
  16.     ListNode<T> *next() { return next_; }
  17.     void setNext( ListNode<T> *newNext ) { next_ = newNext; }
  18.  
  19.     ~ListNode() {
  20.         delete next_;
  21.     }
  22. };
  23.  
  24. template <typename T>
  25. class List {
  26. private:
  27.     ListNode<T> *head_;
  28. public:
  29.     typedef ListNode<T> *iterator;
  30.  
  31.     explicit List() :
  32.         head_( 0 ) {}
  33.  
  34.     void append( const T &data ) {
  35.         if ( head_ == 0 )
  36.             head_ = new ListNode<T>( data );
  37.         else {
  38.             iterator iter = head_;
  39.  
  40.             while ( iter->next() != 0 )
  41.                 iter = iter->next();
  42.  
  43.             iter->setNext( new ListNode<T>( data ) );
  44.         }
  45.     }
  46.  
  47.     iterator begin() { return head_; }
  48.     iterator end() { return 0; }
  49.  
  50.     ~List() {
  51.         delete head_;
  52.     }
  53. };
  54.  
  55. int main() {
  56.     List<int> numbs;
  57.  
  58.     for ( int x( 0 ); x != 10; ++x )
  59.         numbs.append( x + 1 );
  60.  
  61.     List<int>::iterator iter = numbs.begin();
  62.     for (; iter != numbs.end(); iter = iter->next() )
  63.         std::cout << iter->data() << std::endl;
  64. }


Lakrids Jan 12th, 2008 12:06 PM

Re: Friends in inheritance
 
Wow thanks! I'm sure I'll be able to put it to use!


All times are GMT -5. The time now is 4:00 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC