Help with Sending an Object of Class A to a Method of Class B?

I regularly send an object of class X to an external function by reference without problem.

Now that I'm trying to send an object of class A (or in this case a std::vector of Class A objects) to a method within Class B, my compiler refuses with multiple errors, starting with:
"enemy.h(33,36): error C2065: 'Bullet': undeclared identifier"

It's the 'bool enemiesVsBullets(std::vector<Bullet>& laser, int i);' method arguments that it finds unacceptable. ???

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
#pragma once

#include <SDL.h>
#include <SDL_image.h>
#include "window.h"
#include "asset.h"
#include "bullets.h"
#include <string>
#include <iostream>
#include "enemyTextures.h"
#include <vector>


class Enemy
{
public:
	bool _isActive; // Enemy class member varibales
	int _x_ini, _y_ini;
	int _x, _y;
	int _x_target, _y_target;
	int _h, _w, _frame_count, _frame_flag;
	int _state;
	int _xDisplacement;
	int _enemy_ID;

	
	Enemy(bool active, int x_ini, int y_ini, int x, int y, int h, int w, int frame_count, int frame_flag, int state, int xdisp, int id);
		
	void draw(SDL_Texture *enemy_image_texture) const;

	bool rectVsRect(Asset &hero);

	bool enemiesVsBullets(std::vector<Bullet>& laser, int i);
		
	~Enemy();

};
Last edited on
So I tried to make it simpler by only passing the value of a single object of class Bullet to the enemiesVsBullets method within class Enemy.

My compiler is still refusing:
enemy.h(33,24): error C2061: syntax error: identifier 'Bullet'

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
#pragma once

#include <SDL.h>
#include <SDL_image.h>
#include "window.h"
#include "asset.h"
#include "bullets.h"
#include <string>
#include <iostream>
#include "enemyTextures.h"
#include <vector>


class Enemy
{
public:
	bool _isActive; // Enemy class member varibales
	int _x_ini, _y_ini;
	int _x, _y;
	int _x_target, _y_target;
	int _h, _w, _frame_count, _frame_flag;
	int _state;
	int _xDisplacement;
	int _enemy_ID;

	
	Enemy(bool active, int x_ini, int y_ini, int x, int y, int h, int w, int frame_count, int frame_flag, int state, int xdisp, int id);
		
	void draw(SDL_Texture *enemy_image_texture) const;

	bool rectVsRect(Asset &hero);

	bool enemiesVsBullets(Bullet laser);
		
	~Enemy();

};
finally I tried sending an object of class Bullet by reference to enemiesVsBullets method within call Enemy.

Same issue:
enemy.h(33,24): error C2061: syntax error: identifier 'Bullet'

Which I really don't understand - how is the argument (Bullet &laser) any different from the argument of (Asset &hero) in the line above?

The only difference I can see is that object laser belongs to a std:vector<Bullet> laser,
but by the time I call laser as an arguement I've reduced it to a single element object of class Bullet ???

if (enemies[i].enemiesVsBullets(laser[i]) && enemies[enemy_i]._state == 0)

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
#pragma once

#include <SDL.h>
#include <SDL_image.h>
#include "window.h"
#include "asset.h"
#include "bullets.h"
#include <string>
#include <iostream>
#include "enemyTextures.h"
#include <vector>


class Enemy
{
public:
	bool _isActive; // Enemy class member varibales
	int _x_ini, _y_ini;
	int _x, _y;
	int _x_target, _y_target;
	int _h, _w, _frame_count, _frame_flag;
	int _state;
	int _xDisplacement;
	int _enemy_ID;

	
	Enemy(bool active, int x_ini, int y_ini, int x, int y, int h, int w, int frame_count, int frame_flag, int state, int xdisp, int id);
		
	void draw(SDL_Texture *enemy_image_texture) const;

	bool rectVsRect(Asset &hero);

	bool enemiesVsBullets(Bullet &laser);
		
	~Enemy();

};
This is how you probably intend it to work. Sounds like the Bullets class files aren't in the right path

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
#include <iostream>
#include <vector>

class Bullet
{
public:
    Bullet(){std::cout << "Blam!\n";}
    
    ~Bullet(){};
};



class Enemy
{
public:
    Enemy(){std::cout << "Evil\n";}
    
    bool enemiesVsBullets(Bullet &laser)
    {
        std::cout << "This works\n";
        return true;
    }
    
    bool enemiesVsBullets(std::vector<Bullet> &v )
    {
        for(auto i: v)
            std::cout << "This works\n";
        
        return true;
    }
        
    ~Enemy(){};

};

int main()
{
    Enemy nme;
    Bullet b1, b2, b3;
    
    std::vector<Bullet> vec_b;
    vec_b.push_back(b1);
    vec_b.push_back(b2);
    vec_b.push_back(b3);
    
    
    std::cout << nme.enemiesVsBullets(b1) << '\n';
    std::cout << nme.enemiesVsBullets(vec_b) << '\n';
 
    return 0;
}


Evil
Blam!
Blam!
Blam!
This works
1
This works
This works
This works
1
Program ended with exit code: 0


Last edited on
@Nick72c, please stop the stream-of-consciousness posts and submit enough code for people to debug your problem.

What is in bullets.h (where one hopes, presumably, to find the definition of a Bullet)?
Last edited on
Make sure you don't have a circular dependency where enemy.h includes bullets.h and bullets.h includes enemy.h.

Sometimes you can get around this problem by using a forward declaration.

1
2
3
4
5
6
7
8
#include "bullets.h"
class Bullet; // forward declaration

class Enemy
{
public:
	bool enemiesVsBullets(Bullet &laser); // OK
};


There is a limited number of things you're allowed to do with a forward declared class. You can declare (not define) functions that return and take objects of the class as argument, use pointers to objects of the class, etc. but you can not actually write any code that uses the objects.

I'm not sure if you're allowed to declare functions that take a std::vector of the type as argument. It seems to work for me but I'm not sure if it's guaranteed to work.

Vector of incomplete type UB still?
http://www.cplusplus.com/forum/general/272176/

Note that if you solve the problem by using forward declarations you will probably still have to include bullets.h from enemy.cpp. This shouldn't be a problem.


In my own projects I have tried to always use forward declarations instead of includes when possible but only for things in my own headers, not from other libraries, and I've avoided doing it in cases where I'm unsure if it is allowed such as with the std::vector. This reduces the chance of running into these kind of circular include problems trastically and it also speeds up compilation, especially when you've made changes to header files and only need to recompile the .cpp files that include those modified header files.

As far as I've heard, this approach will not work with modules (a new feature that is supposed to be a "better" alternative to headers and includes but support is still lacking). I guess this will either lead to larger modules with multiple classes or we'll have to design our code differently so that the dependency only go in one direction (e.g. Enemy knows about Bullet but Bullet is independent of Enemy). That circular dependencies should be avoided is something that people say so maybe this will force us to write better code. Personally I don't know yet. It'll be interesting to see how this plays out the day the large masses of ordinary programmers start using modules.
Last edited on
enemy.h(33,36): error C2065: 'Bullet': undeclared identifier


The problem seems to be in enemy.h. What is the code for enemy.h ? It isn't included in the given code snippets. Which .h includes it?
Thank you @againtry,
I appreciate you taking the time to look at this. Thank you for confirming that my code concept should work.

I don't think it's a path issue, as all my .cpp and .h files are in the IDE's specified folders, but I think your right in that it's probably more to do with the way the compiler is linking the headers than the actual code.

@lastchance

bullets.h
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
#pragma once

#include <SDL.h>
#include <SDL_image.h>
#include "window.h"
#include "asset.h"
#include "enemy.h"
#include <string>
#include <iostream>
#include "bulletTextures.h"
#include <vector>

class Bullet
{
public:
	float _x; // bullet class member variables
	int _y;
	int _w, _h, _frame_count, _frame_flag;
	bool _active_bullet;
	bool _right_facing;
	int _bullet_time;
	int _enemies_i;
	int _xDisplacement;


	Bullet(float x, int y, int w, int h, int frame_count, bool right, int frameflag);

	void drawbullet(SDL_Texture *bullet_image_texture) const; // Member Function // bullet draw function 

	~Bullet();

};


bullets.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
#include "window.h"
#include "bullets.h"
#include "bulletTextures.h"
#include "enemy.h"
#include "SDL_image.h"
#include <iostream>


Bullet::Bullet(float x, int y, int w, int h, int frame_count, bool right, int frameflag) : // Bullet constuctor 
	_x(x), _y(y), _w(w), _h(h), _frame_count(frame_count), _right_facing(right), _frame_flag(frameflag)
{
	_active_bullet = true;  // mark false to request deletion
	_bullet_time = 0; // do 20 iterations then delete
	_enemies_i = 0;
	_xDisplacement = 0;

}
		
Bullet::~Bullet()
{
	// blank destructor
}


// BULLET DRAW METHOD METHOD 
void Bullet::drawbullet(SDL_Texture* _bullet_image_texture) const // Draw the bullet graphics to the render buffer
{
	int x = int(_x);
	x -= _xDisplacement;

	SDL_Rect source{ 0, ((_h / _frame_count) * _frame_flag), _w, (_h / _frame_count) }; // Source x & y Image Texture coordinates, width, height 
	SDL_Rect destination{ x,_y,_w,(_h / _frame_count) }; // destination rectagle x & y Window coordinates, width, height 

	//std::cout << "Drawbullt x = " << x << "   y = " << _y << "  w = " << _w << "  h = " << _h << "\n \n";

	if (_bullet_image_texture) SDL_RenderCopy(Window::renderer, _bullet_image_texture, &source, &destination); // Render bullet
	else if (!_bullet_image_texture) std::cerr << "Failed to pass texture to _bullet_image_texture - bullet_image_texture. \n";
}



Thank you @Peter87 -
I think this, or something very similar, may be the route cause of the issue.

I'll admit, as my code-base gets larger, with ever more .cpp and .h files. I can start to loose the logic of the includes lists. I'll review this again.


Hi @seeplus,
The first three posts above were all showing enemy.h

Here is the associated enemy.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
#include <iostream>
#include <string>
#include <vector>
#include "SDL.h"
#include "SDL_image.h"
#include "enemy.h"
#include "asset.h"


Enemy::Enemy(bool active, int x_ini, int y_ini, int x, int y, int h, int w, int frame_count, int frame_flag , int state, int xdisp, int id)
	: _isActive(active), _x_ini(x_ini), _y_ini(y_ini), _x(x), _y(y), _h(h), _w(w), _frame_count(frame_count), _frame_flag(frame_flag), _state(state), _xDisplacement(xdisp), _enemy_ID(id)
{
	_x_target = _x_ini;
	_y_target = _y_ini;
}

Enemy::~Enemy()
{
	// blank destructor 
}


void Enemy::draw(SDL_Texture *enemy_image_texture) const // draw the Enemy to the render buffer
{
	SDL_Rect source{ 0, ((_h / _frame_count) * _frame_flag), _w, (_h / _frame_count) }; // Source sprite sheet x, sprite sheet y, Image Texture width, Image Texture height 

	SDL_Rect destination{ _x - _xDisplacement,_y,_w,(_h / _frame_count)}; // destination rectagle x & y Window coordinates, width, height

	if (enemy_image_texture)
	{
		SDL_RenderCopy(Window::renderer, enemy_image_texture, &source, &destination);
		
	}
	else if (!enemy_image_texture)
	{
		std::cerr << "Failed to pass texture to Enemy::draw. \n";
	}

}



bool Enemy::rectVsRect(Asset &hero)
{

return((_x + _w) >= hero._x && _x <= (hero._x + hero._w) && (_y + _h) >= hero._y && _y <= (hero._y + (hero._h / 8)));
}

bool Enemy::enemiesVsBullets(Bullet& shot)
{

return((_x + _w) >= shot._x && _x <= (shot._x + shot._w) && (_y + _h) >= shot._y && _y <= (shot._y + (shot._h / 2)));
}




Nick72c wrote:
Thank you @Peter87 -
I think this, or something very similar, may be the route cause of the issue.

From the code you posted above it is now clear that this is the issue. Note that includes are not "linked". They are essentially just automatic copy pastes.

#include "enemy.h" means include all the code that is in enemy.h as if I had written it here.


Consider the following simplified example:

bullet.h
1
2
3
4
5
6
7
8
9
#pragma once

#include "enemy.h"

class Bullet
{
public:
	
};

enemy.h
1
2
3
4
5
6
7
8
9
#pragma once

#include "bullet.h"

class Enemy
{
public:
	bool enemiesVsBullets(Bullet &laser);
};

test.cpp
1
2
3
4
5
6
#include "bullet.h"

int main()
{
	return 0;
}

When test.cpp is compiled all the content of bullet.h will get included. You can think of it as getting this:

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

class Bullet
{
public:
	
};

int main()
{
	return 0;
}

And after enemy.h has been included you get:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "bullet.h"

class Enemy
{
public:
	bool enemiesVsBullets(Bullet &laser);
};

class Bullet
{
public:
	
};

int main()
{
	return 0;
}

The final include of bullet.h will result in no code being included because that file has already been included and the "#pragma once" in that file prevents it from being included again.

That means you end up with the following code for the compiler to compile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Enemy
{
public:
	bool enemiesVsBullets(Bullet &laser);
};

class Bullet
{
public:
	
};

int main()
{
	return 0;
}

This leads to a compilation error because at the time when the compiler sees Bullet being used as a function parameter in the Enemy class the compiler has no idea what Bullet is. It hasn't been declared yet.


In your code it looks like there is no reason for bullets.h to include enemy.h so if you just remove that include it will probably work.
Last edited on
Thank you @Peter87

That was it.

I went through each .cpp and .h and removed all unnecessary #include statements and everything is working again.

I'll be more circumspect in my application of these in future, I didn't foresee these issues through casual / sloppy includes.


Topic archived. No new replies allowed.