0
#ifndef BUTTONS_H
#define BUTTONS_H

class Window;

class Buttons
{
  friend int main();
  friend void Window::setCloseButtonCaption(string);

public:
    Buttons();
    Buttons(string, Window&);
    ~Buttons();

    void setCaption(string);
    string getCaption();

private:
    string caption;
    const Window * parentWindow;
};

class Window
{

public:
    Window();
    Window(int i, int l,int t, int w, int h, Buttons& B): id(i),left(l), top(t), width(w), height(h), closeButton(B){}
   ~Window(void);

    void setleft(int);
    void settop(int);
    void setw(int);
    void seth(int);

    int getid() const;
    int getleft() const;
    int getwidth() const;
    int getheight() const;
    int getnW() const;

    void Print() const;
    void setCloseButtonCaption(string);

private:
    const int id;
    int left;
    int top;
    int width;
    int height;
    static int numberOfWindows;
    const Buttons closeButton;
};

#endif

The code ran fine until I made the function Window::setCloseButtonCaption(string) a friend of the Buttons class. I tried defining the class Window before the class Buttons but it didn't change. It gave me the errors:

-use of undefined type 'Window'

-see declaration of 'Window'

I'm a beginner by the way, it would be very helpful to provide a detailed explanation. Thanks a lot

Firdaws
  • 93
  • 1
  • 10
  • When you declare a not-so-far-encountered class or freestanding function as `friend`, then it's implicitly declared in the surrounding namespace scope. You can't do that with a member function of an undefined class. The language *could* have supported that, but then there would be a constraint on the later definition of the class, that it provides exactly that function, and that would just complicate things. In an annoying way. In your case I see no need for the `friend` declaration, though. – Cheers and hth. - Alf Mar 18 '16 at 18:48

1 Answers1

1

For class members (unlike free functions) member declaration should be visible before friend declaration.

I would normally suggest to define your Window class before Buttons class to be able to befriend it's members. However, your Window class needs defined Buttons. So, you have possible solutions:

  • Switch to using Buttons by pointer or reference in Window
  • You can make Buttons an inner struct to the Window. Something like that (abridged code)

...

struct Window {
  void setCloseButtonCaption(const std::string& caption);
  struct Buttons {
      friend void Window::setCloseButtonCaption(string);
  };
  Window(int i, int l,int t, int w, int h, Buttons& B): id(i),left(l), top(t), width(w), height(h), closeButton(B){}
};
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • But if he moves the window class to the top, then **Buttons closeButton;** will not compile. – Gam Mar 18 '16 at 18:57
  • @Phantom, yes, this is a fair point. Edited the answer to take care of this. – SergeyA Mar 18 '16 at 19:06
  • I switched to using Buttons by pointer and it worked! Could you explain to me what changed and why it worked? Thanks! – Firdaws Mar 18 '16 at 19:19
  • @Salsabeel, it's hard for me to know what you changed :) – SergeyA Mar 18 '16 at 19:21
  • @SergeyA I just changed the data member closeButton to a pointer. But why didn't it work before and why does it now? :) – Firdaws Mar 18 '16 at 19:29
  • @Salsabeel Because a pointer is always 4 or 8 bytes depending on your compiler settings, so the compiler knows how much space to allocate for **closeButton** if it's a pointer (or a reference). If you use a class that has been declared, but not defined, then the compiler does not know how much space to allocate for that class. Hopefully I've explained myself properly. – Gam Mar 18 '16 at 19:30