0

I am implementing a card game. I want the window ui to be an object of class Rule, so that Rule can modify the GUI directly.

So Rule has an object Window * ui initialized in the constructor.

But during compilation, the compiler tells me that in rule.h, "Window has not been declared", "Window is not a type". I included <window.h>, everything has the same type, everything is initialized, so I run out of ideas of why it does not work.

EDIT: I edited the code following alexisdm's notes. In addition, in rule.h, I had to change the definition of ui from Window * ui to Ui::Window *ui, because in window.h, ui is defined as Ui::Window * ui, and this is the object I want Rule::rule to control.

But now, in rule.cpp, ui->do_stuff() does not compile, because Ui::Window does not have the do_stuff() function, but Window does...

Arg! What to do?!! ui->do_stuff() works fine in window.cpp. Inheritance problem?

window.cpp:

    Window::Window(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Window)
{
    ui->setupUi(this);

    player = new Game_state();                  /* Game state                   */
    rule = new Rule(player, ui);                /* Implement the action of cards*/
}
void Window::do_stuff(){
//Do stuff
}

window.h

#include <QDialog>
#include "game_state.h"
#include "rule.h"

class Rule;
namespace Ui {
    class Window;
}

class Window : public QDialog
{
    Q_OBJECT

public:
    explicit Window(QWidget *parent = 0);
    ~Window();
    Game_state      * player;
    Rule            * rule;
    void do_stuff();

private:
    Ui::Window *ui;
};

rule.h

#ifndef RULE_H
#define RULE_H
#include "window.h"
#include <game_state.h>

class Window;

class Rule{
public:
    Rule(Game_state *, Ui::Window *);
    void action(Card *);

private:
    Game_state * player;
    Ui::Window     * ui;
};


#endif // RULE_H

rule.cpp

    #include <rule.h>

    Rule::Rule(Game_state * game, Ui::Window * window){
        player = game;
        ui = window;
    }
    void Rule::stuff(){
        ui->do_stuff();
    }
Béatrice Moissinac
  • 934
  • 2
  • 16
  • 41

2 Answers2

1

There is a circular dependency in your headers: window.h and rule.h are referencing each other.

You should replace both #include by forward declarations to avoid it.

class Window;  // instead of #include "window.h"
class Rule;  // instead of #include "rule.h"

You'll still need to add #include "window.h" in rule.cpp, and #include "rule.h" in window.cpp.

alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • What is a forward declaration? EDIT: How to use forward declaration in the case of variables? – Béatrice Moissinac Nov 09 '12 at 19:40
  • You should also use include guards in your headers: http://en.wikipedia.org/wiki/Include_guard – Nikos C. Nov 09 '12 at 19:45
  • @NikosC. The include guards are already present, or there would be "multiple definitions" errors. Edit: He just didn't include them in his question, as he didn't know what the problem was... – alexisdm Nov 09 '12 at 19:46
  • @Bibi541 What do you mean by "in the case of variables" ? – alexisdm Nov 09 '12 at 19:49
  • @NikosC.: I have include guards, I just did not include them in the code, alexisdm is right. alexisdm: I used forward declaration for the case where a program has two functions A and B. If function A calls function B, and function B calls function A, then there’s no way to order the functions in a way that they will both be happy. I never used it in the case of variables (Window * ui/ Rule * rule). – Béatrice Moissinac Nov 09 '12 at 19:54
  • 1
    @Bibi541 You can forward declare types that you use only as pointer, reference or function parameter, as long as you don't access the pointed data, which is usually done in the .cpp file where you'll need to use the `#include`. See that [other answer](http://stackoverflow.com/a/553869/894321) for details. – alexisdm Nov 09 '12 at 20:04
  • I updated the code in my question, and reading this other answer made me understand the error the compiler is giving me. Since I can't access/modify the data inside an incomplete type, if I use a forward declaration, this mean that I won't be able to access the data, ever. Therefore, for the use I intend, I should change my architecture, and not use forward declaration. Is this correct? – Béatrice Moissinac Nov 09 '12 at 20:19
  • Since you are also accessing the `Ui::Window` class in `rule.cpp`, you also need to add an `#include "ui_window.h"` (corresponding to the uic/designer generated header) to `rule.cpp`. – alexisdm Nov 09 '12 at 20:26
  • Ah! But now that ui is a Ui::Window *, it does not recognize the functions in window.cpp! (e.g. ui->do_stuff() in rule.cpp returns "Class Ui::Window has no member do_stuff()"! – Béatrice Moissinac Nov 09 '12 at 20:33
  • But ui is Ui::Window, so shouldn't be inherit of the function of Window?? – Béatrice Moissinac Nov 09 '12 at 20:41
  • 1
    Generated Ui classes only contains the widgets of Window, it isn't the window itself. But from a design point of view, Rule shouldn't have direct access to Window::ui (because it is private) or even to the Window object, because the Rule object was created by the Window object, it should have almost no knowledge about the Window object (see the (Law of Demeter)[http://en.wikipedia.org/wiki/Law_of_Demeter] ). If Rule wants to communicate something to Window it could do it with a signal or an event instead. – alexisdm Nov 09 '12 at 23:13
  • That's the lesson of the day I guess. Signal/event are to relationship between objects what a pointer is to passing by reference. This makes so much sense, that they don't have to know about each other. I definitely learned something very important for my coding style. Thanks! – Béatrice Moissinac Nov 10 '12 at 01:20
0

My guess is the name of your class, Window, is too generic and #include <window.h> probably includes the system one instead of yours.

Try change the clase and header name to something more specific to your app like CardWindow, or use #include "window.h"

Stephen Chu
  • 12,724
  • 1
  • 35
  • 46
  • I get exactly the same error "CardWindow has not been declared". I wonder if it is because of namespace Ui{class Window}; ? (cf window.h). Including made the error bigger, because Ui was not defined. – Béatrice Moissinac Nov 09 '12 at 18:36
  • What are you trying to do with the namespace ui? You cannot declare a Window in namespace ui and never define it within that namespace. – schluchc Nov 09 '12 at 18:43
  • I am using Qt Creator. The Ui namespace has been generated by Qt Creator. What I am trying to do is just passing a pointer to Rule::rule, so that Rule::rule can change the GUI directly without having to send back to Window::ui the change needed. – Béatrice Moissinac Nov 09 '12 at 18:50
  • It is justified by the fact that I don't want to implement the rule of the game inside window.cpp, which is just for the GUI. – Béatrice Moissinac Nov 09 '12 at 18:50
  • Did you also change the name of the header file to CardWindow.h? – Stephen Chu Nov 09 '12 at 19:00