How to access elements lower on a chain of inheritance?

Okay the title is kind of vague so I'll do my best to explain. I'm writing the framework for a basic 2d game and each drawable object in the game inherits from a base class, but can also inherit from other classes along this change of inheritance such as NPC or Animating. To update all the objects, I create a vector holding shared pointers to this Base class, and iterate through them and call their virtual function Update(). The issue I'm coming across is whenever I want to access a specific element of one of the derived classes from this vector of Base pointers. So let's say an object in this vector calls its virtual Update() and Attack() another object. However, the object calling Update() only knows that the object is attacking is a Base pointer, so it can't lower the other object's health value or anything because health is owned by NPC which is further down the chain of inheritance. I'll try to explain in code here.
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
#include "stdafx.h"
#include <memory>
#include <iostream>
#include <vector>

class Base{
public:
	Base(){}
	virtual ~Base(){}
	Base(const std::shared_ptr<Base> &object){}
	virtual void Update(const std::shared_ptr<Base> &object){}
};

class NPC : virtual public Base{
public:
	NPC(){}
	virtual ~NPC(){}
	NPC(const std::shared_ptr<Base> &object) : Base(*object){}
	virtual void Update(const std::shared_ptr<Base> &object){
		Attack(object);
	}
	int health;
private:
	void Attack(const std::shared_ptr<Base> &object){
		//object-> health -= 50; //doesn't work

		//let's say I get here, now I want to lower object's health value
		//but I can't because all NPC can see is that object is a Base
		//and doesn't have a health value
		//obiously I can type cast here, but what is a better way?
	}
};

class Object : public NPC{
public:
	virtual void Update(){}
};

int _tmain(int argc, _TCHAR* argv[])
{
	std::vector<std::shared_ptr<Base>> objects;

	//add objects...

	for(int i = 0; i < objects.size(); i++){
		//so to shorten the code, I'm passing an object to Update
		//as if the object has already collided with it and decided
		//to Attack() it
		objects[i]->Update(objects[i + 1]); //okay ignore the error here, it works in my
		//original program for some reason
	}
	return 0;
}

Alright so there are some flaws because it's just a quick example I typed up, but the question stands of how I update all the objects and access their derived elements as well without being able to actually see them.
You can't do it directly. I'm not sure if this is the best way to go about it, but you could have another virtual function inside Base that was something like ReceiveAttack(int damage).

You also might want to look into to whether or not you should be able to attack Base objects anyway; if the only time you would use Attack is when you are attacking another NPC as opposed to an item on the ground or something, just make it an NPC.

You might want to use Base more like an interface (something that is "Updatable"), and store NPC pointers for other things if you want (like Attacking, etc.).
You might want to use Base more like an interface (something that is "Updatable"), and store NPC pointers for other things if you want (like Attacking, etc.).


What do you mean "like an interface"?
You mean something like
1
2
3
4
5
6
7
8
class Base{
//...
NPC *npc;
};


Base b;
b.npc->Attack();

?
Then Base wouldn't be a base at all, it would be an Object.
Last edited on
firedraco means create an abstract class called Updatable, declaring (but not defining) a pure virtual function called "Update()". Now if any object needs updating make its class inherit from class Updatable (some people might define it IUpdatable, I showing it's an interface), and for each of those classes implement it's specific Update method.

Then you can have a list of Updatable objects and to upate them you simply call update in the loop.

1
2
3
4
5
6
std::vector<*Updatable> updateList;
// populate list, then iterate
for(int i=0;i<updateList.size();i++)
{
   updateList.at(i)->Update();
}


syntax might not be right but you get the idea I hope.
Last edited on
But how would this pure virtual Update() allow objects of different types to see the elements of other objects? And I need them all inheriting from the same Base because I need to hold a vector of all of my objects.
you can put this:
 
std::vector<*Updatable> updateList;

wherever you want, and you can make any class inherit from your interface as well.
Sorry but I'm still confused. How could one Updatable pointer see, let's say a health value, of another Updatable pointer?
I'm a bit confused now too :)

you might want to split up two concepts here.
1. objects that can be updated (see the interface example)
2. objects that have a "Kind of" relationship with other objects (inheritance).

edit:
How could one Updatable pointer see, let's say a health value, of another Updatable pointer?

You could have a std::string name member variable in your Base class and then search for them in your list.
Last edited on
Splitting up these concepts might help if all of my objects didn't fit both categories. All of my objects are a kind of Updatable (or Base in my original example).
You could try casting your base class pointer to Player* or Enemy* or whatever using dynamic_cast.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	Player p;
	Enemy e;
	std::vector<Base*> v;
	v.push_back(&e); // And your other entities...
	v.push_back(&p);

	for each (Base* pBase in v)
	{
		pBase->Update();

		Player* pPlayer = dynamic_cast<Player*>(pBase);
		Enemy* pEnemy = dynamic_cast<Enemy*>(pBase);

		if (pPlayer != nullptr) // It's a player!
		{
			pPlayer->TakeDamage(9000);
		}
		else if (pEnemy != nullptr) // It's an enemy!
		{
			pEnemy->DropLoot();
		}
	}

If the cast fails, the result will be a nullptr, else it will be valid.
@Horsht

IMO, casting is not the way to go, polymorphism by sending a pointer to Derived, to something that is expecting a pointer to Base should be enough.

If one needs to do casting, often the design is wrong.

@wh1t3crayon

Just to be sure: Does your vector actually contains pointers to Derived ? (Even though it is correctly declared to take Pointers to Base).

IIRC, we have been through this before, just wanted to clarify that: the correct Update function is called because it works through a pointer to Derived. This is the beauty of declaring containers or functions to accept pointers to Base, but they are given pointers to Derived.

I hope I am not banging on about stuff you already know very well, it's just that your question prompted me to reply in this way.

Regards :+)
Last edited on

Just to be sure: Does your vector actually contains pointers to Derived ? (Even though it is correctly declared to take Pointers to Base).


Yes, I'm pushing pointers (well, shared_ptr's) into the vec of Base shared_ptr's like so:
1
2
std::vector<std::shared_ptr<Base>> vec;
vec.push_back(std::shared_ptr<Derived>(new Derived()));


So then the vec has objects of derived types that call the virtual Update() function. My problem is how to efficiently pass info through this virtual function. Right now, I'm passing several values such as time, interpolation, and the player object through the Update() function, even though some of these parameters aren't even used until a Derived implementation of the function.
1
2
3
4
5
6
7
class Base{
//...
virtual void Update(sf::Time &time, float interpolation){
Move();
//but the parameters aren't even used in this Base implemetation!
}
};

I'm not sure how sloppy the above method is, so I'm really just asking for other ideas for design patterns.

IMO, casting is not the way to go, polymorphism by sending a pointer to Derived, to something that is expecting a pointer to Base should be enough.

If one needs to do casting, often the design is wrong.


Yeah I'm casting a couple of different times already, such as casting in the main game loop to find the correct Player* so I can process the keyboard's input and pass it to the Player*. Also, my current design from earlier with the Attack() problem is that I'm simply casting the passed object into an NPC*, and if it's valid then I lower its health.

I hope I am not banging on about stuff you already know very well, it's just that your question prompted me to reply in this way.

So yeah, in short, I'm quite confused so don't worry about covering an already known topic by me :)
Last edited on
wh1t3crayon wrote:
//but the parameters aren't even used in this Base implemetation!
I'm not sure how sloppy the above method is, so I'm really just asking for other ideas for design patterns.


Hi,

I don't think that matters: part of the idea of an ordinary virtual function is to define behaviour (once) that applies to all it's derived classes. For example:

1
2
3
virtual void CAnimal::Speak() { // CAnimal class is abstract, or at least has a protected ctor
    std::cout << m_Noise << '\n'; // m_Noise is std::string & each derived class has this member variable
}


This means we don't have CowSpeak(), DuckSpeak(), or DogSpeak() functions.

Hopefully your Base class is abstract, or has a protected or private constructor - so that one cannot create an instance of it.

Yeah I'm casting a couple of different times already, such as casting in the main game loop to find the correct Player* so I can process the keyboard's input and pass it to the Player*. Also, my current design from earlier with the Attack() problem is that I'm simply casting the passed object into an NPC*, and if it's valid then I lower its health.


I still don't see the need for that either. With a container (or function accepting) of Base pointer/s, we have already established that they are actually derived pointers, it's just that they are declared as base pointers. All the compiler does is check whether Derived really is derived from Base. This feature allows one to declare the signature for a function once, then either define the function once with an ordinary virtual function, or specialise the function as many times as required in each derived class (from a pure virtual function declaration)

So there are a couple of things that can happen when using a pointer to call a function:

- If the Derived class has a function with the same name as the function being called, it calls that function. That's easy - the pointer is to the derived object.

- If not, then the compiler works it's way up the inheritance tree until if finds a virtual function with that name, and calls it instead, otherwise it's an error.

The other complication is if one has overloaded functions, but the rules are the same whether the function is virtual or not.

Note we are not actually doing anything to the Base class, we shouldn't be able to - because it should be abstract.

So with Player*, a function could be declared to take a pointer to Player, or indeed something higher up like Actor (parent of Player and Enemy) or even GameObject (from which everything derives from). Then the function is called with a pointer to JamesBond or whatever as an argument, the compiler does the right thing - no need for casting.

I agree with firedraco , a RecieveAttack function is a good idea.

BTW, what does NPC stand for?

I know your code was a quick example, I am sure you know that one should not have public member variables like health. Something like a function called AdjustHealth instead.

I also notice you have virtual inheritance, this goes hand in hand with multiple inheritance - is that what you have?


Hopefully this all helps a bit :+)


After reading your reply, I'd say my biggest problem is that my Base class is not abstract. In fact, I had no idea it needs to be. What should a proper Base class look like?

Your code example made sense and that's sort of my implmentation already. I'm running into problem when dealing with the paramaters of a virtual function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Base{
	//...
	virtual void foo(){}
	//notice how foo has open parameters, but if I want DerivedTwo to do foo()
	//with parameters, then I need to give Base::foo(SomeValueType value)
	//that's not a good design, right?
};

class DerivedOne : public Base{
	//...
	virtual void foo(){
		//does DerivedOne something
	}
};

class DerivedTwo : public Base{
	//...
	virtual void foo(SomeValueType value){
		//does something with value
	}
};

That code basically shows my current problem. For some Base pointers, foo() takes a parameter, and for other pointers, I want them to do exactly what foo() does but then extra stuff given a parameter (I say "pointers" here because all instances of my classes are shared_ptr's). BTW, foo() here in my actual code is UpdateObject(), which updates all my game objects, so you can see where some types of objects might need parameters to be passed down while others don't.

The ReceiveAttack() method makes sense, but wouldn't that give all the derived objects lots of extra unecessary "fluff" if I do that enough times?
1
2
3
4
5
6
7
8
class Base{
virtual void Update(){
//used by all derived classes
}
virtual void ReceiveAttack(){
//only used by like 3 classes, just a waste of memory for the rest?
}
};


P.S. thanks for pointing out NPC, it stands for Non Player Character which I just realized the Player inherits from... Well, good thing I'm completely restructuring my code :D
Last edited on
After reading your reply, I'd say my biggest problem is that my Base class is not abstract. In fact, I had no idea it needs to be. What should a proper Base class look like?


Classes (Base or Derived) might be abstract or non-instantiable for a few reasons:

- It might be an interface, that is, has pure or non pure virtual functions for use by all it's derived classes;

- It makes no sense for an object to be created from this class, as in Vehicle:

1
2
      class Car : public Vehicle {};
      class Bus : public Vehicle {};


- The class is a place holder for functions or variables that have been "pushed up the tree" because they are common, as in the Actor class (parent of Player & Enemy) - it holds the health variable.

The ReceiveAttack() method makes sense, but wouldn't that give all the derived objects lots of extra unecessary "fluff" if I do that enough times?


Where one puts a virtual function is a design decision, put it just above the classes that need it. It sounds as though yours is too high up? Don't be afraid to create a new class to achieve this. I mean one might have started with Player & Enemy, then realise that health, Attack(), RecieveAttack() are common, so create the Actor class which Player & Enemy derive from, and put them in there.

Actually, I have just thought of this (which may be a whole better idea):

http://gameprogrammingpatterns.com/contents.html


It talks about how to take Physics, Audio and Animation code out of the Player's code.

Even though it is about components, I think it is still feasible to have hierarchies like Resources etc.

Hope all goes well - Regards


Last edited on
Wow thank you so much for that link; I can't believe I never came across it.

Anyways, I've been thinking about that whole create an interface idea, as well as playing around with aggregation, so I wrote a small sample to test out a new way of organizing my classes. It uses a mixture of composition, aggregation, and inheritance, and frankly I'm still too inexperienced to know how effective this idea is. I'll post the minimal code and really I'm just asking if all the code is safe and in good practice.
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

#include "stdafx.h"
#include <memory>
#include <iostream>

//so for this example I'll create some common interfaces
class Updating{
public:
	virtual void Update() = 0;
virtual ~Updating(){}
};

//each object has its own health values and such
class Living{
public:
	Living(){ health = 0; }
	void SetHealth(int incr){ health = incr; }
	int GetHealth(){ return health; }
private:
	int health;
};

//and some interface classes will carry data which needs to be the same for many objects
class Grid{
public:
	Grid(){ number = 0; }
	int number;
};

//now let's create some aggregations
class Player : public Updating{
public:
	Player(std::shared_ptr<Grid> &grid){
		living.SetHealth(100);
		p_grid = grid;
		p_grid->number = 20;
	}
	virtual void Update(){
		std::cout << "Object health:" << living.GetHealth() << "\n";
		std::cout << "Object shared Grid value:" << p_grid->number << "\n";
	}
private:
    //so some comps will need to be objects by value b/c the values will be independent of every class
    Living living;
	
    //and other comps will be shared_ptrs b/c all objects need to see the same values
    std::shared_ptr<Grid> p_grid;
};

class OtherPlayer : public Updating{
public:
	OtherPlayer(std::shared_ptr<Grid> &grid){
		living.SetHealth(50);
		p_grid = grid;
		p_grid->number = 40;
	}

	virtual void Update(){
		std::cout << "OtherObject health:" << living.GetHealth() << "\n";
		std::cout << "OtherObject shared Grid value:" << p_grid->number << "\n";
	}
private:
	Living living;
	std::shared_ptr<Grid> p_grid;
};

int _tmain(int argc, _TCHAR* argv[])
{
	std::vector<Updating*> vector;
	//the same Grid will be accessed by all classes, so declare it in a higher scope
	std::shared_ptr<Grid> o_grid(new Grid());

	//pass the common classes to the objects
	Player player(o_grid);
	vector.push_back(&player);
	//so this one, abstract func is called and all objects act independently
	vector[0]->Update();

	OtherPlayer op(o_grid);
	vector.push_back(&op);
	vector[1]->Update();

	//shows that the Classes' Living elements are independent, but they see the same Grid elements
	vector[0]->Update();

	return 0;
}


So like the comments say, some interfaces need to be the same for all objects which use them, and other interfaces will have values independent of the other classes' ownerships of those interfaces. My only problems are that I am venturing into new territory with this mixture of association types, and the fact that I am using pointers, which I have yet to get used to. Is this code, or the concept, going to a be a problem?
Last edited on
Hi,

I found this:

http://www.marco.panizza.name/dispenseTM/slides/exerc/eventNotifier/eventNotifier.html


I think this event design pattern might be more suitable to what you are doing. The code is in Java though - I am not sure of the implications of porting that to C++.

I should mention that I haven't implemented one of these myself, nor do I have any experience in implementing Physics, Audio or Animation.

A Google search for C++ design patterns is worthwhile too. Try to use design patterns as much as you can, the abstraction makes it easier to change things later, which is well worth the extra code at the start.

Here's another link, this one has c++ code:

http://dirkriehle.com/computer-science/research/1996/tapos-1996-event.pdf


Another interesting topic is Policy Design. This book is a bit old now (2000) but interesting nonetheless.

http://read.pudn.com/downloads68/ebook/245583/Modern%20C%2B%2B%20Design%20.pdf


Hope all is well at your end :+)

Regards
Yeah thanks, between these links I should be able to improve my code. So to be clear, the code I posted above still wasn't a great design?
Hi,

I am sure your code will be fine up to a point. However using Design Patterns means that the code will be easier to change & extend because of the abstraction. Without it, one finishes up having change things all over the place to accommodate something new. DP often mean a reduction in coupling, or abstracting things so that classes need not be aware of each other, or making it possible to register new things in one place only.

I hope everything goes well, there are plenty of experts here to ask, I am way way way down the list in that regard :+) . Might change my Tag to "TheDabbler" :+D

Regards
Topic archived. No new replies allowed.