Ошибка forward declaration of class

I have an error that goes like this

    In file included from Level.hpp:12,
                 from main.cpp:4:
Corridor.hpp: In method `void Game::Corridor::update()':
Corridor.hpp:41: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:42: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:43: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:44: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'

Corridor and Level are …

  // Corridor.hpp

#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP

#include <Moot/Math.hpp>

//#include <Level.hpp>
#include <GameWindow.hpp>

namespace Game
{
    class Level; // <-- LINE 13

    class Corridor
    {
        static const unsigned int defaultLevelDepth = 800;

        Moot::Math::Vector3D wp1, wp2, wp3, wp4;
        Moot::Math::Vector2D sp1, sp2, sp3, sp4;

        Level * p_level;

    public:

        Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint) 
        {
            wp1 = setFirstPoint;
            wp2 = setSecondPoint;

            wp3 = setFirstPoint;
            wp3.z += defaultLevelDepth;

            wp4 = setSecondPoint;
            wp4.z += defaultLevelDepth;
        }


        void update() {

            sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1); // <- LINE 41 etc.
            sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
            sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
            sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);


            //p_level->getLevelCamera();
        }

        void draw()//const
        {
            Moot::Color tempColor;

            windowInstance().graphics().drawQuad( sp1.x, sp1.y, tempColor,
                                                                                sp2.x,sp2.y, tempColor,
                                                                                sp3.x, sp3.y, tempColor,
                                                                                sp4.x,sp4.y, tempColor, 1);
        }


        void setLevel(Level* setLevel) {
            p_level = setLevel;
        }

    };
}

#endif

and

// Level.hpp

#ifndef GAME_LEVEL_HPP
#define GAME_LEVEL_HPP

#include <Moot/Forward.hpp>
#include <Moot/Window.hpp>
#include <Moot/Math.hpp>

#include <GameWindow.hpp>
#include <Camera.hpp>
#include <Corridor.hpp>
#include <Player.hpp>

#include <vector>


namespace Game
{
    class Level
    {

        typedef Corridor* p_corridor;
        typedef std::vector<p_corridor> CorridorList;
        typedef CorridorList::reverse_iterator ReverseCorridorItter;

        CorridorList m_map;
        Camera       m_camera;
        Player         m_player;


    public:

        Level()
        {
            m_player.setLevel(this);

            // Lots of vertices being defined into m_map.


            // Loop through and set camera
            ReverseCorridorItter rit;

            for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->setLevel(this);


        }


        ~Level()
        {
            ReverseCorridorItter rit;

            for(rit = m_map.rbegin(); rit != m_map.rend(); rit++) 
                delete (*rit);

            m_map.clear();
        }


        void update() 
        {
            // Temp delete when input and player are implimented.
            if(pad[0].buttons & PAD_UP)
                m_camera.updateTargetOffsets(0, -2);

            if(pad[0].buttons & PAD_DOWN)
                m_camera.updateTargetOffsets(0, 2);

            if(pad[0].buttons & PAD_LEFT)
                m_camera.updateTargetOffsets(-2, 0);

            if(pad[0].buttons & PAD_RIGHT)
                m_camera.updateTargetOffsets(2, 0);

            m_player.update();


            ReverseCorridorItter rit;

            for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->update();
        }


        void draw() // const // EH!!! wtf ReverseIter isn't a member
        {
            m_player.draw();


            ReverseCorridorItter rit;

            for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->draw();

        }


        Camera& getLevelCamera() {
            return m_camera;
        }

    };
}

#endif

The pointer is being set as far as I can tell, but when I try to access a function from Level, BOOM!

Thanks.

PS: The compiler is gcc 2.95.2 if that makes a difference.

EDIT

Updated with complete code.

0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

1

13.01.2013, 13:57. Показов 14005. Ответов 13


Студворк — интернет-сервис помощи студентам

Привет!
Есть два класса, один создаёт другой и передаёт в него ссылку на самого себя, чтобы тот мог вызывать некоторые функции первого. Получается такое перекрёстное использование.

Но, проблемы с компиляцией:
ISO C++ forbids declaration of ‘мой класс’ with no type

Я прочитал, что надо вместо #include «мой класс.h» вставить class мой класс; но это тоже не помогло:
forward declaration of ‘struct мой класс’

Можете помочь с инфой как правильно декларировать в таком случае? Нужно решение независимо от компилятора.
Благодарю!



0



Croessmah

Неэпический

17819 / 10592 / 2044

Регистрация: 27.09.2012

Сообщений: 26,636

Записей в блоге: 1

13.01.2013, 14:06

2

Цитата
Сообщение от Setneros
Посмотреть сообщение

Можете помочь с инфой как правильно декларировать в таком случае? Нужно решение независимо от компилятора.
Благодарю!

А код?
Что-то мне подсказывает, что в объявлении класса Вы пытаетесь написать реализацию. Распихайте реализацию по разным .cpp, объявления по разным .h и опережающие объявления поставьте.
И еще — необходимо в классе делать указатели на классы, а не объекты классов. Иначе банально ничего работать не будет.
То есть вот так не получится:

C++
1
2
3
4
5
6
7
8
9
10
class B;
class A{
    B b;
};
class B{
    A a;
};
int main() {
    A a;
}



1



Setneros

0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 14:25

 [ТС]

3

Цитата
Сообщение от Croessmah
Посмотреть сообщение

C++
1
2
3
4
5
6
7
8
9
10
class B;
class A{
    B b;
};
class B{
    A a;
};
int main() {
    A a;
}

Мой случай:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
B.h
#include "A.h"
class B(A * aPointer)
{
    //  Some with aPointer
}
 
 
A.h
#include "B.h"
class A
{
    B b(this);
}
 
 
main.cpp
#include "A.h"
int main() {
    A a;
}



0



Неэпический

17819 / 10592 / 2044

Регистрация: 27.09.2012

Сообщений: 26,636

Записей в блоге: 1

13.01.2013, 14:29

4

Цитата
Сообщение от Setneros
Посмотреть сообщение

class B(A * aPointer)

Это что?

Цитата
Сообщение от Setneros
Посмотреть сообщение

B b(this);

А это?



0



Setneros

0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 14:54

 [ТС]

5

Цитата
Сообщение от Croessmah
Посмотреть сообщение

Это что?

А это?

Указатель породившего класса
Мне нужно выполнять некоторые функции A класса находясь внутри B класса

Добавлено через 23 минуты
Извиняюсь, может быть непонятно написал, теперь исправил:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
B.h
#include "A.h"
class B
{
     B(A * aPointer);
}
 
 
A.h
#include "B.h"
class A
{
    B b(this);
}
 
 
main.cpp
#include "A.h"
int main() {
    A a;
}



0



vxg

Модератор

3376 / 2148 / 352

Регистрация: 13.01.2012

Сообщений: 8,341

13.01.2013, 15:06

6

Цитата
Сообщение от Setneros
Посмотреть сообщение

B b(this)

запись не имеет смысла + вам уже сказали что при таком опережающем использовании нельзя возвращать объекты (нужно возвращать указатели).

C++
1
2
3
4
5
6
7
8
9
class a;
class b
{
    a *p;
};
class a
{
    b *p;
};



1



Setneros

0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 15:25

 [ТС]

7

Цитата
Сообщение от vxg
Посмотреть сообщение

C++
1
2
3
4
5
6
7
8
9
class a;
class b
{
    a *p;
};
class a
{
    b *p;
};

Как тогда в классе b вызвать функцию породившего его класса a?
В вашем коде я вижу что a создаёт b, но b не имеет доступа к функциям и данным конкретно породившего его класса a…



0



Модератор

3376 / 2148 / 352

Регистрация: 13.01.2012

Сообщений: 8,341

13.01.2013, 15:35

8

никто никого не создает. просто в классах есть указатели на объекты другого класса. вызвать метод можно через p->do_something()



1



DU

1500 / 1146 / 165

Регистрация: 05.12.2011

Сообщений: 2,279

13.01.2013, 15:36

9

сказали же нужно просто растащить правильно по h и cpp файлам:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// B.h
class A;
class B
{
public:
    B(A* a);
};
 
// A.h
class A
{
public:
    A();
 
    void foo();
};
 
// B.cpp
#include "A.h"
#include "B.h"
B::B(A* a)
{
    a->foo();
}
 
// A.cpp
#include "A.h"
#include "B.h"
A::A()
{
    B b(this);
}
 
void A::foo()
{
  //...
}



1



0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 15:41

 [ТС]

10

Цитата
Сообщение от vxg
Посмотреть сообщение

никто никого не создает. просто в классах есть указатели на объекты другого класса. вызвать метод можно через p->do_something()

Вы видимо меня немного не допонимаете.
Мне не хочется создавать другой объект класса, когда уже есть один — класс, создавший текущий класс. Потому что это может быть затратно по ресурсам.

Мне нужен способ вызвать функцию этого создавшего текущий класс класса.



0



Setneros

0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 16:12

 [ТС]

11

Цитата
Сообщение от DU
Посмотреть сообщение

сказали же нужно просто растащить правильно по h и cpp файлам:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// B.h
class A;
class B
{
public:
    B(A* a);
};
 
// A.h
class A
{
public:
    A();
 
    void foo();
};
 
// B.cpp
#include "A.h"
#include "B.h"
B::B(A* a)
{
    a->foo();
}
 
// A.cpp
#include "A.h"
#include "B.h"
A::A()
{
    B b(this);
}
 
void A::foo()
{
  //...
}

Попробовал, куча ошибок.
Вот проект на Qt и скриншот ошибок.

Миниатюры

Forward declaration
 

Вложения

Тип файла: zip TestDeclaration2.zip (5.0 Кб, 7 просмотров)



0



ComfyMobile

401 / 282 / 34

Регистрация: 24.07.2012

Сообщений: 916

13.01.2013, 16:20

12

класс объект, объект класс, у ТС каша в голове, вам в любом случае нужно будет 2 объекта иначе никак

Добавлено через 1 минуту
а еще можете попробовать сформулировать более глобальное задание, потому что скорее всего его можно решить иначе чем такая вот отвратительная конструкция



0



Неэпический

17819 / 10592 / 2044

Регистрация: 27.09.2012

Сообщений: 26,636

Записей в блоге: 1

13.01.2013, 16:21

13

Цитата
Сообщение от Setneros
Посмотреть сообщение

Попробовал, куча ошибок.

Вот точно такой код компилируется без проблем. Что-то, где-то Вы намудрили!



1



0 / 0 / 0

Регистрация: 13.01.2013

Сообщений: 9

13.01.2013, 16:25

 [ТС]

14

Цитата
Сообщение от Croessmah
Посмотреть сообщение

Вот точно такой код компилируется без проблем. Что-то, где-то Вы намудрили!

Да, простите, виноват.
Заголовочные два раза добавил. Странно, что Creator проглотил.
Вопрос решён, Спасибо!



0



I have the following errors trying to use a TFT library function inside my library. My library uses the pointer to an instance of the TFT library in the constructor, as well described there:

Basic C++ programming, how to pass constructor argument into class?

The errors are:

error: invalid use of incomplete type 'class TFT'
_TFTscreen->background(0, 0, 0);

error: forward declaration of 'class TFT'
class TFT;

MESmenu.h:

#ifndef _MESMENU_H_
#define _MESMENU_H_

#include <SPI.h>
#include <SD.h>

class TFT;

class MESmenu{
public:
  MESmenu(TFT* pTFT) : _TFTscreen(pTFT) {};
  void start();
  void execute();
private:
  TFT* _TFTscreen;
};

#endif

MESmenu.cpp:

#include "Arduino.h"
#include "MESmenu.h"

void MESmenu::start(){
  _TFTscreen->background(0, 0, 0);
  _TFTscreen->text("starting menu...", 0, 0);
  //...
}

void MESmenu::execute(){
   //some code...  
}

The Arduino sketch is:

#include <SPI.h>
#include <SD.h>
#include <TFT.h>  // Arduino LCD library
#include <MESmenu.h>  // my library

// --------- TFT LCD ---------
// pin definition for the due
#define sd_cs  7
#define lcd_cs 10
#define dc     9
#define rst    8
TFT TFTscreen = TFT(lcd_cs, dc, rst);

// MES menu class
MESmenu *mainMenu = new MESmenu(&TFTscreen);

void setup() {
  // initialize TFT
  TFTscreen.begin();
  TFTscreen.background(0, 0, 0);
  // set the stroke color to white
  TFTscreen.stroke(255,255,255);
  TFTscreen.fill(255,255,255);
  TFTscreen.setTextSize(2);
  TFTscreen.text("TEST", 0, 0);

  // Start menu
  mainMenu->start();
}

void loop () {
  mainMenu->execute();      
}

The problem is related to the function:

_TFTscreen->background(0, 0, 0);

inside the MESmenu::start() in the .cpp file.

UPDATE:

As suggested by frarugi87 I’ve updated the question with the details of .h and .cpp files.
Those file are in the ArduinolibrariesMESmenu folder.

I try to change

class TFT;

with

#include <TFT.h>

and removed the #include from the main arduino sketch.

This leads to the following errors:

librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: first defined here

librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read16(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here

librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read32(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here

librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::loadImage(char const*)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here

Forward declarations and Invalid uses of incomplete type Init

Alright, I don’t know why I should have unresolved dependency issues here, but here goes:

And to think, I was just trying to build a simple class for initializing SDL facilities.

All the tutorials I’ve been doing (lazyfoo) seem really cluttered and have all this initialization data up-front in nested if-statements in main.cpp, and I thought it looked sloppy and that I’d do one better by encapsulating all that crap into a simple class for my own uses.

Having done thirty of them, I thought I knew enough to start screwing around on my own. Maybe not?

Init.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>

class Init()
{
    public:
    bool initAll();
    bool initVid();
    void initVSync();
    void initLinTextFilt();
    bool initWindow(SDL_Window* winArg);
    bool initRenderer(SDL_Window* winArg, SDL_Renderer* rendArg)
    bool initTTF();
    bool initIMG();
};

(Ignore the «magic consts» in the window creation function, they’re just placeholders for variables I have yet to declare.)
Init.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "Init.h"

//calls all other Initialization functions
bool Init::initAll(SDL_Window* window, SDL_Renderer* renderer)
{
    initVid();
    initVSync();
    initLinTextFilt();
    initWindow(window);
    initRenderer(window, renderer);
    initTTF();
    initIMG();
}
//Initialize SDL Video subsystem
bool Init::initVid()
{
    bool success = true;
    if(!SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf("SDL_INIT_VIDEO failed. SDL Error: %sn", SDL_GetError());
        success = false;
    }
    return success;
}
//Initialize vertical synchronization
void Init::initVSync()
{
    if(!SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"))
    {
        printf("Warning: VSync not enabled.");
    }
}
//initialize linear texture filtering
void Init::initLinTextFilt()
{
    if(!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
    {
        printf("Warning: Linear texture filtering not enabled.");
    }
}
//initialize window
bool Init::initWindow(SDL_Window* winArg)
{
    bool success = true;
    winArg = SDL_CreateWindow("Default Title", SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
    if(winArg == NULL)
    {
        printf("Window could not be created! SDL error: %sn", SDL_GetError())
        success = false;
    }
    return success;
}
//initialize renderer
bool Init::initRenderer(SDL_Window* winArg, SDL_Renderer* rendArg)
{
    bool success = true;
    rendArg = SDL_CreateRenderer(winArg, -1, SDL_RENDERER_ACCELERATED);
    if(gRenderer == NULL)
    {
        printf("Renderer could not be created! SDL error: %sn", SDL_GetError())
        success = false;
    }
    else
    {
        SDL_SetRenderDrawColor(rendArg, 0x00, 0x00, 0x00, 0xFF);
    }
}
//Initialize TrueType Font subsystem
bool Init::initTTF()
{
    bool success = true;
    if( TTF_Init() == -1 )
    {
        printf( "SDL_ttf could not initialize! SDL_ttf Error: %sn", TTF_GetError() );
        success = false;
    }
    return success;
}
//Initialize PNG loading subsystem
bool Init::initIMG()
{
    bool success = true;
    int imgFlags = IMG_INIT_PNG
    if (!(IMG_Init(imgFlags)&imgFlags))
    {
        printf("SDL_Image could not initialize! SDL_Image Error: %sn", IMG_GetError() );
        success = false;
    }
    return success;
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
#include "Init.h"

//global vars
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;

//main execution
int main(int argc, char* [] args)
{
    initAll(gWindow, gRenderer);
}

build messages (backspaced over long directory names for convenience)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dirInit.h|6|error: expected unqualified-id before ')' token|
dirInit.cpp|4|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|15|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|26|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|34|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|42|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|55|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|70|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
dirInit.cpp|81|error: invalid use of incomplete type 'class Init'|
dirInit.h|6|error: forward declaration of 'class Init'|
||=== Build finished: 17 errors, 0 warnings (0 minutes, 0 seconds) ===|

Look at line 14 of Init.h. There’s something missing…

A couple of things jump off the page:

— The brackets on line 6 of Init.h shouldn’t be there,
— The declaration and definition of initAll don’t match (one has no parameters, the other has two parameters)

Thanks a ton guys. Sometimes I just need a second pair of eyes that aren’t tired.

I gotta leave for work now, but I’ll take your advice when I get back!

Thanks in advance for any additional help.

Line 6 of Init.h:

1
2
3
4
5
6
7
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>

class Init //() <- you don't put parenthesis on class definitions.  Only for functions.
{

Also these are non-static members of a class, so you need to have an object to act on.

1
2
3
4
5
6
7
int main(int argc, char* [] args)
{
    // initAll(gWindow, gRenderer);  <- won't work because initAll isn't global

    Init obj;  // <- have to create an Init object
    obj.initAll( gWindow, gRenderer );
}

But of course… having an ‘Init’ object doesn’t really make much sense. Can you have multiple Inits? Does having the object actually do anything?

These functions are all global by nature. Rather than putting them in a class, maybe put them in a namespace:

1
2
3
4
5
6
7
8
9
10
11
12
namespace Init
{
   bool initAll();
   ...
}

//...

int main()
{
    Init::initAll( ... );
}

Or… if you don’t want a namespace… then make it a static class that can’t be instantiated (though that is more work for little gain).

Remember the whole point of a class is to represent a ‘thing’. They’re nouns.

Common examples of classes and what they represent:
std::string — represents a string
std::fstream — represents a file
std::list — represents a linked list of objects
etc

What exactly does an ‘Init’ represent? It’s not a ‘thing’, so it doesn’t really need to be a class.

Ah, thank you Disch. I wasn’t sure if classes NEEDED objects or not and I had forgotten about creating namespaces. I thought it was conventional to have objects of classes, but not mandatory. I had tried converting it to a struct before posting this thread, but obviously that didn’t work.

And I had thought about making an Init object (which would require me to write a constructor) but it occurred to me, like you said in your post, that it made no sense.

I’ll eventually remember all this if I fail enough times. :P

EDIT:

Disch! I noticed in your namespace example that you put the namespace Init member functions in main, is that truly necessary? The whole reason I decided to do this whole wrapper class thing was to keep excess stuff out of main. Should I define the functions inside the namespace, instead? Will that create problems because it’s inside a header?

Edit 2: Never mind the previous edit. Everything is in order now.

Last edited on

Topic archived. No new replies allowed.

Solution 1

In order to define a class or struct, the compiler has to know how big each member variable of the class is. A forward declaration does not do this. I’ve only ever seen it used for pointers and (less often) references.

Beyond that, what you’re trying to do here cannot be done. You cannot have a class A that contains an object of another class B that contains an object of class A. You can, however, have class A contain a pointer to class B that contains an object of class A.

B.cpp

#include "B.h"

void B::SomeFunction()
{
}

B.h

#ifndef __B_h__  // idempotence - keep header from being included multiple times
#define __B_h__
#include "A.h"

class B
{
public:
    A a;
    void SomeFunction();
};

#endif // __B_h__

A.h

#ifndef __A_h__  // idempotence - keep header from being included multiple times
#define __A_h__
#include "B.h"

class B; // forward declaration

struct A
{
    B *b;  // use a pointer here, not an object
};

#endif // __A_h__

Two points. First, be sure to use some form of idempotence to keep the headers from being included multiple times per compilation unit. Second, understand that in C++, the only difference between classes and structs is the default visibility level — classes use private visibility by default while structs use public visibility by default. The following definitions are functionally equivalent in C++.

class MyClass
{
public: // classes use private visibility by default
    int i;
    MyClass() : i(13) { }
};

struct MyStruct
{
    int i;
    MyStruct() : i(13) { }
};

Solution 2

Forward declarations, like

struct A;

or

class A;

Introduce A as an incomplete type and it remains incomplete until end of type’s definition is reached. There are things you can do with incomplete types and things you can’t. You can

  1. Declare variables (or members) of type «pointer to A» and «reference to A»
  2. Declare functions which take arguments of type A or return type A

You can’t

  1. Declare variables (nor members) of type A
  2. Dereference pointers to A or access any members of references to A
  3. Define subclasses of A.

In your code you try to declare struct member of incomplete type. It’s illegal. Only pointers and references are allowed.

Solution 3

public:
    A a;

You are trying to create the object of A with only forward declaration. Compiler at this moment ( with only forward decl) cannot decide the size of the object A and hence, it cannot allocate memory required for A. So you cannot create objects with only forward decl.

Instead replace with:

A* a;

Pointer or reference to A without A’s class definition will work fine.

Solution 4

Two issues jump out at me here.

1: You’ve written Struct A instead of struct A; note the lower-case «s». Your compiler might consider the equivalent, but I don’t think it’s standard C++.

You have defined a circular reference between A and B. Each A object must contain a B object, but each B object must contain an A object! This is a contradiction, and will never work the way you want it to. The usual C++ way to solve that problem is to use pointers or references for A::b or B::a (or both).

Related videos on Youtube

ITERATORS in C++

17 : 09

Forward Declaration of Class C++

05 : 05

Forward Declaration of Class C++

C++ Header Files

15 : 10

Learning C++ STL - Forward List

10 : 14

Learning C++ STL — Forward List

C++/Game Tutorial 10: Parameters and Forward Declarations!

09 : 22

C++/Game Tutorial 10: Parameters and Forward Declarations!

C++ Class declaration | Part-1/2 | OOPs in C++ | Lec-13 | Bhanu Priya

15 : 41

C++ Class declaration | Part-1/2 | OOPs in C++ | Lec-13 | Bhanu Priya

Modern C++ CLASSES - Easy and In-depth explanation | All the basics you need with examples!

27 : 48

Modern C++ CLASSES — Easy and In-depth explanation | All the basics you need with examples!

C++ for C# and Java Developers

39 : 47

C++ for C# and Java Developers

C++11 Perfect Forwarding

17 : 24

UE4 C++ Tutorial - #Include and Forward Declarations - UE4 / Unreal Engine 4 Intro to C++

08 : 47

UE4 C++ Tutorial — #Include and Forward Declarations — UE4 / Unreal Engine 4 Intro to C++

C++ Forward Declaration Objects/Enums

02 : 19

C++ Forward Declaration Objects/Enums

Forward Declarations | Introduction to Programming with C++ | Part 43

04 : 09

Forward Declarations | Introduction to Programming with C++ | Part 43

Forward Declaration - Beginner C++ Tutorials

02 : 13

Forward Declaration — Beginner C++ Tutorials

Comments

  • The follwing code is compiled in VC++6. I don’t understand why I am getting the compilation error C2079: 'b' uses undefined class 'B' for the following code.

    Class B Source

    #include "B.h"
    
    void B::SomeFunction()
    {
    }
    

    Class B Header

    #include "A.h"
    
    struct A;
    
    class B
    {
        public:
            A a;
            void SomeFunction();
    };
    

    struct A Header

    #include "B.h"
    
    class B;
    
    struct A
    {
        B b;
    };
    

    If I changed class B header to the following, then there will be no error. But the header declaration won’t be at the top!

    Class B Header with weird header declaration

    struct A;
    
    class B
    {
         public:
            A a;
            void SomeFunction();
    };
    
    #include "A.h"
    

  • In the actual code, preprocessor macros are defined but it is not shown here to make the code simpler.

  • Double-underscores are reserved for the compiler. Use a different naming convention.

  • Double-underscores are reserved for the compiler. Use a different naming convention.

  • @GMan: I’ve always used this convention for my idempotence markings when the compiler doesn’t generate them automatically. Is this specific to a compiler or is it in the C++ spec?

  • @Matt, it is part of the C++ spec that such identifiers are reserved. I personally use «HEADER_PATH_TO_HEADER_H_INCLUDED» or «HEADER_PATH_TO_HEADER_INCLUDED» (if no «.h»).

Recents

Related

  • Ошибка fortniteclient win64 shipping exe системная ошибка
  • Ошибка fortnite на андроид
  • Ошибка fortnite game security violation
  • Ошибка formex dll отсутствует clsid
  • Ошибка former volume not mounted торрент