tags:

views:

68

answers:

3

Hello,

I'm receiving the forbids declaration without type error in a Qt application I'm working on. The problem is that I have included the header file which declares the class. It should be defined as a type as far as I can tell. I tried forward declaration as well, but I'd like to use the methods of the class in this file and so I need the whole header file. code:

Shapes.h

#ifndef SHAPES_H
#define SHAPES_H

#include "Colors.h"
#include <QPoint>
#include "glwidget.h"

//class GLWidget;  

class Shape
{
    public:

        virtual void draw();
};

class Rectangle : public Shape
{
    public:
        Rectangle(GLWidget *w, QPoint tl, QPoint br);

        virtual void draw(){
              // top horizontal
            for(int i = topLeft.x(); i < btmRight.x(); i++){
                 glWidget->setPixel(i,topLeft.y(), color);
             }
        }

    private:
        QPoint topLeft,btmRight;
        GLWidget *glWidget;        /****  This is the Error line  ****/
        RGBColor color;
};

#endif // SHAPES_H

glwidget.h:

#ifndef AGLWIDGET_H
#define AGLWIDGET_H

#include <QGLWidget>

#include "Colors.h"
#include "Shapes.h"

class GLWidget : public QGLWidget
{
    Q_OBJECT

public:
    GLWidget(QWidget *parent = 0);
    ~GLWidget();

    QSize minimumSizeHint() const;
    QSize sizeHint() const;

    void setPixel(int x, int y, RGBColor c);

public slots:
    void setColor(RGBColor c);
    void setDrawRectangle();



protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int width, int height);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

private:

    QPoint lastPos;
    QVector<QPoint> drawPoints;
    RGBColor paintColor;
    int drawmode;
    Shape *currentShape;

};


#endif

I don't see why I can't use my GLWidget in Shapes.h. The error is in Shapes.h on the line where I declare GLWidget *glWidget; If I use a forward declaration ie. class GLWidget; this error goes away but then I can't actually use the GLWidget methods as in Rectangle.draw()

Anyone have an idea why the compiler wouldn't see GLWidget as a type in Shapes.h?

Exact errors:

Shapes.h:20: error: expected ')' before '*' token
Shapes.h:31: error: ISO C++ forbids declaration of 'GLWidget' with no type
Shapes.h:31: error: expected ';' before '*' token
Shapes.h: In member function 'virtual void Rectangle::draw()':
Shapes.h:25: error: 'glWidget' undeclared (first use this function)
Shapes.h:25: error: (Each undeclared identifier is reported only once for each function it appears in.)

+1  A: 

The reason is the include order - you use a circular inclusion and only the include guards prevent you from looping the compiler.
You can resolve this in your particular case by forward-declaring the shape class in glWidget.h and removing the include for Shapes.h:

//#include "Shapes.h"
class Shape;
dark_charlie
+6  A: 

You have a circular dependency between your header files -- Shapes.h includes glwidget.h, which includes Shapes.h again. So, the second time the compiler tries to include glwidget.h, the include guard AGLWIDGET_H has been defined, so it doesn't include it again, and then the code in Shapes.h tries to use types that ought to have been declared but are not.

To fix it, you need to remove one of the dependencies and use forward declarations instead. Since glwidget.h doesn't actually use the Shape class beyond declaring a pointer member variable, you should remove its inclusion of Shapes.h:

glwidget.h:

#ifndef AGLWIDGET_H
#define AGLWIDGET_H

// do NOT include Shapes.h

class Shape;  // forward declaration

class GLWidget : public QGLWidget
{
    ...
    Shape *currentShape;
};

#endif

Shapes.h is the same as before:

#ifndef SHAPES_H
#define SHAPES_H

#include "glwidget.h"
...
#endif
Adam Rosenfield
Solid explanation, +1.
Platinum Azure
This solves the current situation, but the code provided is not a complete implementation. GLWidget WILL need to know methods of Shape classes. There must be some way for me to have them included in both?
wallacer
hmm actually I suppose just glwidget.cpp needs to actually know the methods of Shape classes so I can include Shapes.h in glwidget.cpp?
wallacer
Thanks that works
wallacer
@wallacer: Yes, glwidget.cpp needs to include Shapes.h, but that's ok because it doesn't create a circular dependency (since nothing includes glwidget.cpp).
Adam Rosenfield
great thanks for the help, can't believe this is the first time I've run into this!
wallacer
I'd recommend moving the Shape class into its own header file (since really, it's probably just an interface anyway), and renaming Shapes.h to Rectangle.h. Then you can include shape.h from both files without problems.
cHao
A: 

Just guessing ... but try

#endif

instead of

#endif // SHAPES_H
pmg
Cause everyone knows comments are the devil.
cHao
Because I've seen a `C` compiler that didn't like extra spaces after preprocessing lines *(and the `C` standard defines `#endif` it as `"# endif new-line"` (6.10.1))*
pmg
See 5.1.1.2, particularly step 3 of the process. Comments are removed at the same time the preprocessor directives are found. But then, **C++ isn't C**, so i'm not even sure why we're consulting the C standard on this anyway.
cHao
Because initially the question was tagged with `c`. And notice I said extra spaces, not extra comments (5.1.1.2/3): "Each comment is replaced by one space character."
pmg
Back to 6.10 for a second. Note that *none* of the definitions mention any whitespace besides newlines. But also note that all of them allow such space -- and most, of them actually *require* some separation of tokens in order to function as we expect them to. (`#ifdef SHAPES_H` would be wrong if WS weren't implicitly allowed.)
cHao