简体   繁体   中英

C++: invalid use of incomplete type

First of all I want to apologize for my english. I'm afraid that is not my born language. I'm going crazy with this code.

I'm making a little engine to make games. I implemented a class called "process" that is the class that will inherit all the elements that make up the game. What happens is that by implementing two of these elements so that inherit from "process" the compiler throws me the following error:

||=== Build: Debug in MotorSDL (compiler: GNU GCC Compiler) ===|
include/mainProcess.h  |6 | error: invalid use of incomplete type ‘class process’
include/declarativas.h |65| error: forward declaration of ‘class process’
include/exeControl.h   |6 | error: invalid use of incomplete type ‘class process’
include/declarativas.h |65| error: forward declaration of ‘class process’
/home/yawin/Dokumentuak/c/MotorSDL/src/engine.cpp |  | In destructor ‘virtual Engine::~Engine()’:
/home/yawin/Dokumentuak/c/MotorSDL/src/engine.cpp |11| warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
/home/yawin/Dokumentuak/c/MotorSDL/src/engine.cpp |  | In member function ‘void Engine::update()’:
/home/yawin/Dokumentuak/c/MotorSDL/src/engine.cpp |76| warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
||=== Build failed: 4 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|

I have read many of the issues in this respect have been published on this forum before and I understand that the mistake is that I am not correctly using a class (the class "process") because not instantiate properly or because it lacks something to the class (a required method not implemented).

But as I read and check my code I can't find where I'm making the mistake. Is anyone able to see what I'm wrong?

Here is the source code: https://github.com/yawin123/SDLEngine

"main.cpp"

#include <SDL2/SDL.h>
#include "declarativas.h"

int main()
{
    Engine *e = new Engine(true);
    e->newWindow("Hola mundo", SDL_WINDOW_OPENGL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_RENDERER_ACCELERATED);

    e->newTask(new exeControl());
    do
    {
        e->run();
        SDL_Delay(1);
    }while(e->isRunning());

    e->destroyWindow();

    return 0;
}

"include/declarativas.h"

#ifndef DECLARATIVAS_H
#define DECLARATIVAS_H

enum keyCode
{
    _esc,
    _1, _2, _3, _4, _5, _6, _7, _8, _9, _0,
    _minus, _plus,
    _backspace,
    _tab,
    _q, _w, _e, _r, _t, _y, _u, _i, _o, _p,
    _a, _s, _d, _f, _g, _h, _j, _k, _l,
    _z, _x, _c, _v, _b, _n, _m,
    _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12,
    _enter,
    _c_enter,
    _control,
    _l_shift,
    _comma,
    _point,
    _r_shift,
    _c_asterisk,
    _prn_scr,
    _alt,
    _caps_lock,
    _num_lock,
    _scroll_lock,
    _home,
    _c_home,
    _up,
    _c_up,
    _pgup,
    _c_minus,
    _left,
    _c_left,
    _c_center,
    _right,
    _c_right,
    _c_plus,
    _end,
    _c_end,
    _down,
    _c_down,
    _pgdn,
    _c_pgdn,
    _ins,
    _c_ins,
    _del,
    _c_del,
    _less,
    _equals,
    _greater,
    _asterisk,
    _r_alt,
    _r_control,
    _l_alt,
    _menu,
    _l_windows,
    _r_windows,
    _close_window,
    _FOO_KEY
};

class Engine;
class process;
class Ventana;

//Procesos
class mainProcess;
class exeControl;

#include "process.h"
#include "engine.h"
#include "Ventana.h"

#include "mainProcess.h"
#include "exeControl.h"

#endif // DECLARATIVAS_H

"include/process.h"

#ifndef PROCESS_H
#define PROCESS_H

#include "engine.h"
#include "declarativas.h"

class process
{
    public:
        process();
        process(Engine *e);
        virtual ~process();

        virtual void Update();

        int id;
        int father;

        void setEngine(Engine *e);

    protected:
        Engine *engine;
};

#endif // PROCESS_H

"src/process.cpp"

#include "process.h"

process::process(){return;}
process::process(Engine *e)
{
    setEngine(e);
}

process::~process()
{
    return;
}

void process::setEngine(Engine *e)
{
    engine=e;
}

void engine::Update()
{
    return;
}

"include/engine.h"

#ifndef ENGINE_H
#define ENGINE_H

#include "Ventana.h"
#include "process.h"
#include "declarativas.h"

#include <SDL2/SDL.h>
#include <vector>
#include <iostream>
using namespace std;

class Engine
{
    public:
        Engine(bool debug=false);
        virtual ~Engine();
        void run();

        void newWindow(string i_title, int i_windowMode, int i_posX, int i_posY, int i_width, int i_height, int i_rendererMode);
        void destroyWindow();
        Ventana* ventana;

        /**Ciclo de ejecución**/
            void input();
            void update();
            void render();
        /*********************/

        /**Control de ejecución*******/
            bool isRunning();
            void isRunning(bool m_r);
            bool m_run=true;
        /*****************************/

        vector<process*> taskManager;   //Gestor de procesos
        int newTask(process *task);     //Dar de alta procesos

        SDL_Event event;    //Evento para controlar teclado
        bool key[_FOO_KEY]; //Array de teclas pulsadas

        /**Control de debug*******/
            bool isDebug;
            void Debug(string t);
            void Debug(int t);
            void Debug(float t);
        /************************/
};

#endif // ENGINE_H

"src/engine.cpp"

#include "engine.h"

Engine::Engine(bool debug)
{
    isDebug=debug;
    SDL_Init(SDL_INIT_VIDEO);
}

Engine::~Engine()
{
    for(int i=0;i<taskManager.size();i++)
    {
        delete(taskManager[i]);
    }
    taskManager.clear();

    delete(ventana);
    SDL_Quit();
}

void Engine::newWindow(string title, int windowMode, int posX, int posY, int width, int height, int rendererMode)
{
    if(ventana)
    {
        destroyWindow();
    }
    ventana = new Ventana(title,windowMode,posX,posY,width,height,rendererMode);
}

void Engine::destroyWindow()
{
    delete(ventana);
}

void Engine::run()
{
    input();
    update();
    render();
}

void Engine::input()
{
    for(int i=0;i<_FOO_KEY;i++)
    {
        key[i]=false;
    }

    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT: //Si pulsamos el botón de cerrar ventana
                key[_close_window]=true;
                break;

            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                    case SDLK_ESCAPE:
                        key[_esc]=true;
                        break;

                    default:
                        break;
                }
                break;

            default:
                break;
        }
    }
}
void Engine::update()
{
    for(int i=0;i<taskManager.size();i++)
    {
        taskManager[i]->Update();
    }
}
void Engine::render()
{
    ventana->render();
}

bool Engine::isRunning()
{
    return m_run;
}
void Engine::isRunning(bool m_r)
{
    m_run=m_r;
}

int Engine::newTask(process *task)
{
    taskManager.push_back(task);
    taskManager[taskManager.size()-1]->setEngine(this);
    return taskManager.size()-1;
}

void Engine::Debug(string t)
{
    if(isDebug)
        cout<<t<<endl;
}
void Engine::Debug(int t)
{
    if(isDebug)
        cout<<t<<endl;
}
void Engine::Debug(float t)
{
    if(isDebug)
        cout<<t<<endl;
}

"include/mainProcess.h"

#ifndef MAINPROCESS_H
#define MAINPROCESS_H

#include "process.h"

class mainProcess : public process
{
    public:
        mainProcess();
        virtual ~mainProcess();

        virtual void Update();
};

#endif // MAINPROCESS_H

"src/mainProcess.cpp"

#include "mainProcess.h"
mainProcess():process(){}
mainProcess::~mainProcess(){}

void mainProcess::Update()
{
    return;
}

"include/exeControl.h"

#ifndef EXECONTROL_H
#define EXECONTROL_H

#include "process.h"

class exeControl : public process
{
    public:
        exeControl();
        virtual ~exeControl();

        virtual void Update();
};

#endif // EXECONTROL_H

"src/exeControl.cpp"

#include "exeControl.h"

exeControl::exeControl():process(){}
exeControl::~exeControl(){}

void exeControl::Update()
{
    if(engine->key[_esc] || engine->key[_close_window])
    {
        engine->isRunning(false);
    }
}

I think you don't need the rest of the classes. But if you need, you can find in the link to github above.

You have a circular inclusion issue.

process.h includes engine.h and engine.h includes process.h . You need to break this cycle. This is usually done with using forward declarations and pushing includes in the the source files.

At a quick glance it looks like you can do a forward declaration of process in engine.h and remove the include.

Note: Often you include a header in the header file of a class and in the source file of the same class but it's not necessary in the header already includes it.


Example Issue

Foo.h

#ifndef FOO_H
#define FOO_H

#include "Bar.h"

class Foo
{
private:
    Bar* mBar; // Raw pointer should actually be an appropriate smart pointer type
};

#endif

Foo.cpp

// Nothing required here for this example

Bar.h

#ifndef BAR_H
#define BAR_H

#include "Foo.h"

class Bar
{
private:
    Foo mFoo;
};

#endif

Bar.cpp

// Nothing required here for this example

In the above there is a circular inclusion issue; the include guards have nothing to do with fixing this issue. Furthermore, since Foo only uses a pointer to a Bar instance a forward declaration can be used to break the cycle.


Example Solution

Foo.h

#ifndef FOO_H
#define FOO_H

// Note: #include "Bar.h" is removed
class Bar; // This forward declares the `Bar` class

class Foo
{
private:
    Bar* mBar; // Raw pointer should actually be an appropriate smart pointer type
};

#endif

Foo.cpp

#include "Bar.h"

Bar.h

#ifndef BAR_H
#define BAR_H

#include "Foo.h"

class Bar
{
private:
    Foo mFoo;
};

#endif

Bar.cpp

// Nothing required here for this example

You have a case of cyclic dependency here: Engine class uses process and process uses Engine . This is often an indicator of a flawed architecture.

If all you care for is resolving the compilation issue, forward declaration should do the trick: remove either "process.h" from "engine.h" (or vice versa) and declare

class process;

in the "engine.h" header.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM