Class A members depends on Class B members: how to?

Pages: 12
Hello everyone,
i spot here from time to time when i come back to c++ development.
I have a question:

Assuming i have a class BackGround as follow:

1
2
3
4
5
6
7
8
9
  class BackGround : public GameObject
{
public:

	void draw();
	void update();
	
private:
float screenXCoord, screenYCoord;


I would like to update the two private members screenXCoord and screenYCoord that are responsible of the moving (or scrolling) background. The background screenXCoord and screenYCoord class member depends on the ship movement and position of the class ShipPoly that have two members shipX and shipY:

1
2
3
4
5
6
7
8
9
10
11
class ShipPoly : public PolygonGameObject
{

public:

	void draw();
	void update();
...

private:
float shipX, shipY;


In the ShipPoly update function i update the position of the ship.
Since the ship act as a camera when i move the ship i would like to move or scroll the background updating the screenXCoord and screenYCoord properties.

How can i do this?

Thank you very much
Can you define a function in Background that takes a const ShipPoly, read its shipX, shipY values and assign them to screenXCoord, screenYCoord?
It sounds like you want to use a member function in the ShipPoly class to modify a member variable of the BackGround class?

If that's all, then just make the ShipPoly class a friend of the BackGround class and write your functions accordingly.

You may also want to make your functions virtual if you're using derived classes (which it looks like you are), so you can override the base class member functions and avoid possible errors.

I may be wrong, if that's not what you want then just ignore me. Also, it might help if you posted a bit more code.
Thank you all for the reply.

@agent max

Yes, this is what i want to achieve. Before posting this question i logged in the cplusplus forum and there was (on the front page) the very tutorial about the friend class.

I tried without success :-(

In clas BackGround i declared the ShipPoly class as friend. This way ShipPoly should access the private and protected members screenXCoord and screenYCoord of the BackGround class. If i try to set i.e. screenXCoord = 20 in ShipPoly, i get error: ‘screenXCoord’ was not declared in this scope.

Could you please give me an example?

The code above is derived from SDL game programming book.
As per the two classes... there is nothing much else, but the implementation.




Last edited on
In clas BackGround i declared the ShipPoly class as friend. This way ShipPoly should access the private and protected members screenXCoord and screenYCoord of the BackGround class. If i try to set i.e. screenXCoord = 20 in ShipPoly, i get error: ‘screenXCoord’ was not declared in this scope.


Making ShipPoly a friend of Background allows a ShipPoly object to access the private members of a Background object.

However, there still needs to be a Background object for the ShipPoly object to access. You need to pass the Background object to the ShipPoly object, so that the ShipPoly object can change its members.
@MikeyBoy

Thank you for the additional informations. I was just wondering how ShipPoly knows about BackGround object, since the friendship relationship is unilateral?

How to pass the Background object to ShipPoly then?
I was just wondering how ShipPoly knows about BackGround object


In your Background class, you have declared friend ShipPoly;, yes?

This means that ShipPoly has permission to access the private members of a Background object.

That is all it means.

It doesn't magically give ShipPoly a Background object to modify; your code has to provide that in the same way it would provide ShipPoly with any other data (e.g. by passing it as an argument to the appropriate method).

It doesn't magically provide to ShipPoly the definition of the Background class; your code has to provide that in the the same way as it would provide any other definition (e.g. by #include-ing the relevant header file).

How to pass the Background object to ShipPoly then?

That depends entirely on your code design. If there's only one Background object, then probably best to pass it as an argument to the ShipPoly constructor, and have ShipPoly store it as a data member, and modify it each time it updates.

If, on the other hand, there are multiple Background objects, and you want to choose which one to modify at the time you call ShipPoly::update(), then you should pass it as an argument to that method.
Last edited on
Thank you again for the reply.

There is only one background.
 
GameObject* background = new BackGround(new LoaderParams(0, 0, 1920, 1080, "background"));


This is the GameObject class:

1
2
3
4
5
6
7
8
9
10
11
12
13
class GameObject
{
public:
	
	virtual void draw() = 0;
	virtual void update() = 0;
	virtual void clean() = 0;

protected:

	GameObject(const LoaderParams* pParams) {}
	virtual ~GameObject() {}
};


Here i instantiate the ShipPoly:

 
PolygonGameObject* shipPolygon = new ShipPoly(new LoaderParams("polyShip", ""), ?BackGround?);


What the correct way to pass the BackGround object and then store it as a data member? I should pass the BackGround object class, not the GameObject* background...
Last edited on
–You need to have a BackGround object in the ShipPoly class as a member.
–Then you can pass a BackGround object, by either value or reference, to your overloaded constructor.
–Then have your overloaded constructor copy the values from the passed object to the member object.

Am I making sense? I know my explanation isn't the best, if you need clarification I'll try to explain better.

Note: for the third part, if you get an error that says something like: "Implicit copy constructor not viable," then you will need to make a custom copy constructor.

Good luck!
max
This is the GameObject class:
protected: virtual ~GameObject() {}
It is probably a mistake to define a protected virtual destructor.

Less concretely, deriving everything from a semantically-empty "object" class is not a great start.

Sorry to all for the late reply.

I really appreciated all the answers.

I need to study again.

I didn't succeed in this:

"–You need to have a BackGround object in the ShipPoly class as a member.
–Then you can pass a BackGround object, by either value or reference, to your overloaded constructor.
–Then have your overloaded constructor copy the values from the passed object to the member object."

I will try again asap.

Thank you very much.

Kind regards


–You need to have a BackGround object in the ShipPoly class as a member.
–Then have your overloaded constructor copy the values from the passed object to the member object.

Are you sure that's necessary? Do you want ShipPoly to store a copy of the BackGround object? Or would it make more sense for it simply to store a pointer or reference to the single BackGround object?
Last edited on
Yes, using a pointer or reference to a single object would be a better way to do it. I didn't suggest that because I am not sure of the OP's skill level, and too many different suggestions might be confusing.
Well, if the function is intended to modify the same object as is being accessed by the calling code, then creating a copy would be explicitly a bad choice, and will outright fail to do what the OP wants. This is an important choice, and not one to be handwaved away.

And since the OP is already using pointers in the code they've posted, I don't see any reason to think they'd be confused by them.
An object should be modified via its interface. Setters/getters are part of interface. Friendship is too.

Given two objects:
1
2
GameObject* background = ...
PolygonGameObject* shipPolygon =  ...

Who does the work?
1
2
3
background->one( shipPolygon ); // GameObject::one() uses data from shipPolygon
shipPolygon->two( background ); // PolygonGameObject::two() writes to background
three( background, shipPolygon ); // standalone three() uses both objects 

Whether the "use" and "write" are via friend access or getters/setters is up to you.

GameObject::one() is a setter. It uses getters of PolygonGameObject or friendship.
PolygonGameObject::two() uses setters of GameObject or friendship.

So, who should do the work? That is up to you.




1
2
PolygonGameObject* shipPolygon
      = new ShipPoly(new LoaderParams("polyShip", ""), ?BackGround?);

What the correct way to pass the BackGround object and then store it as a data member? I should pass the BackGround object class, not the GameObject* background...

Does ShipPoly have a BackGround member?
OR
Does constructor of ShipPoly just update an unrelated BackGround object during initialization of ShipPoly object?

1
2
3
4
5
6
7
8
GameObject* background = ...

BackGround* real = dynamic_cast<BackGround*>( background );
if ( real ) {
  // real points to a BackGround object and can be used
} else {
 // background does not point to a BackGround object 
}
Last edited on
@mbozzi

Sorry, i tried to follow the book example and sources. Please consider that i come back to c++ from time to time.

As per the code i don't know the correct way to pass the background object to the shipPoly class (see the questions marks) or rather I thought I knew, but trying to pass the Background object by reference I received errors.

1
2
3
4
GameObject* background = new BackGround(new LoaderParams(0, 0, 1920, 1080, "background"));

PolygonGameObject* shipPolygon
      = new ShipPoly(new LoaderParams("polyShip", ""), ???BackGround???);


this is the constructor of the shipPoly:

 
ShipPoly::ShipPoly(const LoaderParams* pParams, ???BackGround background???) : PolygonGameObject(pParams) {


What the correct way to pass the object to the shipPoly class and how the ShipPoly constructor should look like?

Thank you all in advance
Last edited on
You... just pass it the same way as you'd pass any other object. I mean, you already know how to do that, because you're already doping it the code you've written - e.g. in line 4 of the snippet in your most recent post, you're already passing one object into the constructor of ShipPoly, so... what's confusing you about passing a second one?
@MikeyBoy

this is what i'm doing:

1
2
GameObject* background = new BackGround(new LoaderParams(0, 0, 1920, 1080, "background"));
PolygonGameObject* shipPolygon = new ShipPoly(new LoaderParams("polyShip", ""), background);


the shipPoly.h constructor:

 
ShipPoly(const LoaderParams* pParams, BackGround background);


shipPoly.cpp

 
ShipPoly::ShipPoly(const LoaderParams* pParams, BackGround background) : PolygonGameObject(pParams) {


I get the error:
ShipPoly.cpp|9|error: no matching function for call to ‘BackGround::BackGround()’|
Last edited on
1
2
3
4
5
6
7
// the parameters in call:
( new LoaderParams("polyShip", ""), background )
// types of parameters:
( LoaderParams*, GameObject* )

// ctor declaration:
ShipPoly( const LoaderParams*, BackGround );

The LoaderParams* can be used as const LoaderParams*. That is OK

The GameObject*, a pointer type is definitely not a Background. Error


If you dereference the pointer, then you access the object:
new ShipPoly(new LoaderParams("polyShip", ""), *background )

However, can you construct a Background object from GameObject? Probably not.
How would you do that?
A Background is a GameObject (due to inheritance), but a GameObject is not a Background.


PS. Why do you use new everywhere?
Do you have all the necessary delete too?
Why do you pass almost everything with pointers, except the background?
Thank you @keskiverto for your informative considerations.

As per the use of the new operator, i tried to follow the examples on the SDL Game programming book, that seems very well done. The problem is that when i needed to do specific things (move a background using the ship as a camera) i run into this problem, mixing inheritance and other OOP related concepts in the wrong way.

The GameObject*, a pointer type is definitely not a Background. Error


Yes, if i pass the object as a GameObject i get:
ShipPoly.h|13|error: cannot declare parameter ‘background’ to be of abstract type ‘GameObject’|

What about a little online session? :-)
Pages: 12