Wzajemne #include w 2 klasach

0

Witam wszystkich użytkowników forum.
W ramach ćwiczeń piszę sobie małą gierkę w c++ z wykorzystaniem SFML 2.1.
Napotkany problem wygląda tak:

Mam 2 klasy:

  • Character (postać która jest bohaterem gry)

  • Bullet (pocisk, którego używa postać)

Obiekt klasy Bullet jest atrybutem klasy Character.

//Character.h

#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <Bullet.h>

enum STATE {GO_LEFT, GO_UP, GO_RIGHT, GO_DOWN, STOP};

class Character
{
    public:
        Character(sf::RenderWindow & window, int localize = 0);
        ...
    private:        
        Bullet * bullet1;
        ...
 
//Bullet.h

#pragma once
#include <SFML/Graphics.hpp>
#include "Character.h"

class Bullet
{
    public:
        Bullet(Character * p);
        void draw(sf::RenderWindow & window);
        sf::Vector2f get_position();

        bool moving;
        ...
    private:
        Character * owner;
        ...

Próba kompilacji:

include/Bullet.h:8:26: error: expected ‘)’ before ‘*’ token
         Bullet(Character * p);
                          ^
include/Bullet.h:16:9: error: ‘Character’ does not name a type
         Character * owner;
         ^
 

Dlaczego klasa Bullet nie widzi klasy Character pomimo załączenia pliku nagłówkowego?

1
class Bullet;
class Character
  {
...

class Character;
class Bullet
  {
...
0

Co daje taki zapis, i dlaczego bez tego nie działa?
Pierwszy raz się spotkałem z takim problemem i interesuje mnie jego geneza.

PS
Zapomniałem o typie enumaracyjnym STATE, którego też nie widać z poziomu klasy Bullet. Co z tym zrobić?

0

http://en.wikipedia.org/wiki/Circular_dependency

Kryształowa kula podpowiada że nie dołączyłeś deklaracji tego STATE.

1

Jeżeli zastąpisz pragma once starym sposobem( z define) to będzie to wyglądać tak

#ifndef _CHARACTER_H_
#define _CHARACTER_H_
#include <BULLET.h>

class Character{
...

Oznacza to że w momencie załączania pliku Bullet.h, nie mamy jeszcze żadnej wiedzy o klasie Character, natomiast gdy z pliku Bullet.h, załączamy Character.h "nie przechodzi" on przez ifdefa. Tym samym nie mamy żadnej wiedzy o tej klasie.

Błąd wychodzi już w czasie projektowania. Klasa Bullet najprawdopodobniej nie musi mieć wiedzy, o tym kto nim strzelił, sprawdzenie natomiast możesz dokonać po stronie postaci. Nie wiem w jakim celu dodałeś tą informację, więc nie podam przykładu jak to lepiej zrobić :(

0

Ehh.. Może inaczej. W jaki sposób ją dołączyć?

0

Wykład z podstaw C/C++ specjalnie dla @gośćabc:
Mamy trzy pliki:

  1. main.cpp
#include <iostream>
//#include "a.h"
#include "b.h"

int main() 
  {
	  return 0;
  }
  1. a.h
#ifndef _A_H_
#define _A_H_
#include "b.h"

//class B;
class A
  {
   public:
   B *b;
  };

#endif
  1. b.h
#ifndef _B_H_
#define _B_H_
#include "a.h"

//class A;
class B
  {
   public:
   A *a;
  };

#endif

Przy kompilacji dostajemy: [Error] 'B' does not name a type w wierszu 9 a.h
Jeżeli odkomentujemy wiersz 2 w main.cpp to dostaniemy [Error] 'A' does not name a type w wierszu 9 b.h
Aby tego się pozbyć odkomentujmy wiersz 5 w b.h teraz się kompiluje,
ale jeżeli znów zakomentujemy wiersz 2 w main.cpp to znowu dostaniemy: [Error] 'B' does not name a type w wierszu 9 a.h
Aby tego się pozbyć odkomentujmy wiersz 5 w a.h teraz się kompiluje niezależnie od tego który z plików a.h czy b.h zostanie dołączony do pliku.

0

dzięki za lekcję, i ten świetny przykład jak nie kodować w c++

zrób ten test, to może czegoś się nauczysz

http://jonjagger.blogspot.co.uk/2013/04/the-include-test.html

ja raczej jestem za tym, abyś Ty przestał się udzielać w tym dziale, za napisanie powyższego postu;

a tak przy okazji to nie jest temat dla początkujących

0

@gośćabc,
Gdyby stwierdziłeś coś w rodzaju: - "wystarczy poprawi błąd projektowy" to nie ma tematu dyskusji.
Nic nie mówisz o błędzie projektowym, zaś stwierdzasz "... jeżeli ma definicję klasy w nagłówku character.h, to nie potrzebna jest forward deklaracja ...". Ja udowodniłem że ten fragment twojej wypowiedzi to kompletne bzdury, nie mówimy tu o wzorcu projektowym. Ale pewnie zaraz stwierdzisz że ten fragment oznacza jedno z dwóch:
a) Trawa jest zielona;
b) Niebo jest błękitne.
Wg mnie konstrukcja zdania "... jeżeli ma ..., to nie potrzebna ..." ewidentnie oznacza że wypowiedź nie ma nic wspólnego ani z trawą ani z niebem ani ze błędem projektu.

Druga część tejże wypowiedzi: - "... forward deklaracja tu wystarczy i nie trzeba includować całego nagłówka ..." - też może okazać się bzdurą bo masz w podanym kodzie wszędzie ... czyli całkiem możliwa jest funkcja zdefiniowana w ciele klasy korzystająca że składowych innej klasy, więc może się okazać że nie wystarczy forward deklaracji. Rozumiem że ta część twojej wypowiedzi oznacza jedno z dwóch:
a) Jest rok 2014
b) Piszemy na forum 4programmers.
Tu dokładnie to samo konstrukcja zdania nie pozostawia wątpliwości - nie piszesz o błędzie w projekcie ani o roku ani o forum na którym piszemy.

Podkreślam raz jeszcze że nigdzie nic nie powiedziałeś o błędzie projektowym i nie to jest tematem dyskusji.
Co do sarkastycznego podejścia - to już zrezygnowałem z wpajania dobrych wzorców projektowych, bo przez te wszystkie lata mojej obecności na tym forum ani razu nikt wytknięciem błędu projektowego się nie przyjął.

1 użytkowników online, w tym zalogowanych: 0, gości: 1