utilizarea invalidă a declarației de tip incomplet / forward (Programare, C++, Gcc, Declarație De Înaintare, Tip Incomplet)

rivon a intrebat.

Am încercat să mă uit la problemele similare listate aici pe Stackoverflow și pe Google, dar acestea se referă în principal la șabloane și nu este cazul meu. Folosesc GCC 4.4.5 pe Debian Testing 64bit.
Așadar, am două clase – CEntity:

#ifndef CENTITY_H_INCLUDED
#define CENTITY_H_INCLUDED

#include "global_includes.h"

// game
#include "CAnimation.h"
#include "Vars.h"
#include "vector2f.h"
#include "Utils.h"

class CAnimation;

class CEntity
{
public:
    CEntity();
    virtual ~CEntity();

    void _update(Uint32 dt);

    void updateAnimation(Uint32 dt);

    void addAnimation(const std::string& name, CAnimation* anim);
    void addAnimation(const std::string& name, const CAnimation& anim);
    void removeAnimation(const std::string& name);
    void clearAnimations();

    bool setAnimation(const std::string& name);

    SDL_Surface* getImage() const;

    const vector2f& getPos() const;
    const vector2f& getLastPos() const;
    F getX() const;
    F getY() const;
    F getLastX() const;
    F getLastY() const;
    SDL_Rect* getHitbox() const;
    SDL_Rect* getRect() const;

    F getXSpeed() const;
    F getYSpeed() const;

    void setPos(const vector2f& pos);
    void setPos(F x, F y);
    void setPos(F n);
    void setX(F x);
    void setY(F y);

    void setHitboxSize(int w, int h);
    void setHitboxSize(SDL_Rect* rect);
    void setHitboxWidth(int w);
    void setHitboxHeight(int h);

    void setSpeed(F xSpeed, F ySpeed);
    void setXSpeed(F xSpeed);
    void setYSpeed(F ySpeed);

    void stop();
    void stopX();
    void stopY();

    void affectByGravity(bool affect);

    void translate(const vector2f& offset);
    void translate(F x, F y);

    bool collide(CEntity& s);
    bool collide(CEntity* s);

protected:
    CAnimation* mCurrentAnimation;
    SDL_Surface* mImage;

    vector2f mPos;
    vector2f mLastPos;
    SDL_Rect* mHitbox; // used for collisions
    SDL_Rect* mRect; // used only for blitting

    F mXSpeed;
    F mYSpeed;

    bool mAffByGrav;

    int mHOffset;
    int mVOffset;

private:
    std::map<std::string, CAnimation*> mAnims;
};

#endif // CENTITY_H_INCLUDED

și CPlayerChar care moștenește din CEntity:

#ifndef CPLAYERCHAR_H_INCLUDED
#define CPLAYERCHAR_H_INCLUDED

#include "global_includes.h"

// game
#include "CEntity.h"

class CEntity;

class CPlayerChar : public CEntity
{
public:
    CPlayerChar();
    virtual ~CPlayerChar();

    virtual void update(Uint32 dt) = 0;

    virtual void runLeft() = 0;
    virtual void runRight() = 0;
    virtual void stopRunLeft() = 0;
    virtual void stopRunRight() = 0;

    virtual void attack() = 0;
    virtual void stopAttack() = 0;

    virtual void attack2() = 0;
    virtual void stopAttack2() = 0;

    virtual void ground() = 0;
    virtual void midair() = 0;

    void jump();
    void stopJump();

protected:
    // looking right?
    bool mRight;

    bool mJumping;
    bool mOnGround;
    bool mGrounded;
};

#endif // CPLAYERCHAR_H_INCLUDED

Când încerc să le compilez, GCC aruncă această eroare:

CPlayerChar.h:12: error: invalid use of incomplete type ‘struct CEntity’
CPlayerChar.h:9: error: forward declaration of ‘struct CEntity’

Am încercat mai întâi fără declarația forward ‘class CEntity;’ în CPlayerChar.h pe linia 9, dar apoi ar arunca acest lucru în schimb

CPlayerChar.h:12: error: expected class-name before ‘{’ token

Deci declarația forward trebuie să fie acolo. De asemenea, CEntity este în mod clar o clasă, nu o structură.

Comentarii

  • În C++, clasele și structurile sunt aproape identice; nu vă lăsați prins de mesajul de eroare. –  > Por Mark Ransom.
  • Presupun că definiția clasei pentru CEntity se află în fișierul CEntity.h? Dacă nu, aceasta este problema dumneavoastră. –  > Por Mark Ransom.
  • Aveți o includere circulară în fișierele de antet. Un fișier de antet ar trebui să includă alte fișiere de antet numai dacă este necesar în mod explicit. Dacă puteți utiliza o declarație directă, atunci ar trebui să preferați acest lucru. –  > Por Martin York.
3 răspunsuri
Martin York

Aveți o includere circulară în fișierele de antet.
Dar fără toate fișierele de antet nu vom putea să o rezolvăm.

Eu aș începe de aici.

#include "CAnimation.h"

Dacă te uiți la antetul tău, de fapt nu ai nevoie de asta. Folosești CAnimation doar prin referință sau pointer, așa că declarația forward pe care o ai ar trebui să fie suficientă. Mutați include-ul în fișierul sursă (adică în afara antetului).

Următorul loc în care m-aș uita este:

#include "global_includes.h"

Orice includere globală inclusă într-un fișier antet ar fi bine să fie foarte simplă. Ar trebui să conțină doar tipuri simple și să nu includă alte fișiere de antet (cu excepția cazului în care acestea sunt la fel de simple). Orice lucru complex va duce la probleme cu dependențele circulare.

Regula generală de bază

Un fișier de antet ar trebui să includă numai fișierele de antet de care are absolută nevoie. În caz contrar, acestea ar trebui să fie incluse din fișierul sursă. Aveți nevoie în mod absolut de un fișier antet numai dacă definește o clasă care este utilizată ca clasă părinte, dacă aveți membri obiecte ale acelei clase sau dacă utilizați obiecte parametru ale acelei clase.

Eu folosesc termenul object pentru a face distincție față de referințe sau pointeri. Dacă le folosiți pe acestea din urmă, nu este necesar să includeți fișierul antet. Trebuie doar să faceți o declarație forward.

Comentarii

  • În legătură cu dependențele circulare, dacă are #ifndef CANIMATION_H_INCLUDED, nu ar trebui ca problema să fie prevenită? –  > Por antogerva.
  • @antogerva Asta ajută, dar nu este suficient. Trebuie, de asemenea, să declarați înainte tipurile. De asemenea, includeți doar antetele de care aveți nevoie în mod specific și declarați înainte alte tipuri. –  > Por Martin York.
André Puel

Probabil că aveți o buclă în incluziunile dvs. în așa fel încât CPlayerChar nu știe cine este cu adevărat CEntity, știe doar că există, dar nu știe ce este.

Dacă eliminați declarația „class CEntity”, veți vedea că GCC se va plânge că CEntity nu există.

Trebuie să verificați că nimic din ceea ce include CEntity nu include CPlayerChar.

Comentarii

  • Mulțumesc, ultimul rând al tău trebuie să fie acela. CEntity include un alt fișier care include CEntity și CPlayerChar. Acum trebuie doar să găsesc o soluție de rezolvare. –  > Por rivon.
Kerrek SB

Trebuie să vă asigurați că fișierul complet definiție completă a clasei CEntity este vizibilă în punctul în care definiți clasa CPlayerChar. (Deci, verificați incluziunile.)

Acest lucru se datorează faptului că puteți moșteni numai din clasele complet definite, dar nu și din cele declarate în avans.

Singurul moment în care puteți scăpa cu declarații directe în loc de definiții complete este atunci când faceți pointeri sau referințe la un tip, dar numai dacă nu accesați niciodată niciunul dintre membrii acestuia sau (datorită lui @Alf) atunci când declarați o funcție cu tip de retur incomplet.

Comentarii

  • Declarațiile forward sunt un pic mai puternice decât pare să indicați. De exemplu, dacă T este un tip incomplet, atunci declararea unei funcții T foo() este perfect în regulă. Pentru a o apela trebuie să aveți T completat (cu excepția cazului în care T este tipul special void, care în mod formal este un tip incomplet care nu poate fi niciodată completat), dar aceasta este o altă problemă. 🙂 –  > Por Salutări și hth. – Alf.
  • @Alf: Mulțumesc! Asta e util. Dar parametrii de funcție, pot fi incompleți? –  > Por Kerrek SB.