Vector of Object

Okay, I'll try to explain the issue I've ran into:

Let's say I have two classes named NPC and MOVER. Both of those classes are derived from a class named SPRITE. NPC and MOVER both have a tick() function and a paint() function that is called to tick and draw them respectively, that's not my issue though.

When a map is loaded into my program, I would like to add these classes to a vector when needed. I would like to be able to have both MOVER and NPC (and in the future, more) objects kept in a vector like this:
 
vector sprites<SPRITE>


Calling the functions works fine (assuming that the functions are put in the sprite class as virtual functions, blah blah blah) when I do something along the lines of:

1
2
sprites[i].tick();
sprites[i].paint();


What if MOVER has a variable (Let's call it MVAR) that only it will use, and I don't want to define it in SPRITE because NPC (and many more) classes don't need it. How can I access this variable from outside the NPC class? An example:
1
2
3
4
5
6
Pseudo Code:

if(sprites[i].id=="NPC"){ //If the classes id is marked as a NPC, blah
    //We know it's an NPC, let's check what his message is to determine some miscellaneous stuff!
    cout<<sprites[i].MVAR;
}


If I try and do this, I get an error. I'm very tired (and aggravated at many dead ends on trying to find a solution online) so if someone could (with detail please) point me in the right direction or please give me an example, I would be very grateful. I've see that dynamic_cast may be a solution, but I don't understand how I could use it here. I've also heard that it can be very slow if called often, but I'm not sure about if that's correct.

Any help would be extremely welcome and as I said earlier, an example showing some basic ways to accomplish what I'm trying to do here would be wonderful, as I can work with an example better than explanations (both are even better though). If someone could just write some pseudo code with the class and variable names I supplied, I think I could work most everything out for myself.

Sorry for any mistakes, I'm very tired. I have tried searching (and testing) much more than I would have liked too.
How are you instantiating your objects?

Can you provide a code example of how you're declaring the instances and pushing them to the vector?
To get the behavior you want you need to hold pointers or references in your sprites vector. You'll get slicing if you try to push an NPC or MOVER into a vector of SPRITE.
@iHutch105

Something along the lines of...
1
2
3
4
5
6
MOVER moverTemplate;
NPC npcTemplate;

//Set load map stuff, do this when a npc / mover is detected in map
//Set npcTemplate options like x,y, random stuff
sprites[i].push(npcTemplate); //Adds a npc with all the properties I set 


@cire

That sounds like what some of my searching yielded, would you care to go into more detail on how I would do that?
This assumes that the container should manage the lifetime of the objects you are pointing to. That may not be a valid assumption, in which case lines 123 onward and the use of smart pointers may not apply.

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <string>
#include <vector>
#include <iostream>
#include <memory>

class Base
{
public:

	virtual std::string name() const
	{ return "Base" ; }

	// classes meant to be inherited from should have
	// a virtual destructor.
	virtual ~Base() {}
};


class Derived_1 : public Base 
{
public:
	std::string name() const { return "Derived_1" ; }

	void setAddedData(int value) {added_data = value;}
	int getAddedData() const {return added_data;}

private:

	int added_data ;


};

class Derived_2 : public Base
{
public:
	std::string name() const { return "Derived_2" ; }

	void setOtherData(std::string s) { other_data = s ; }
	std::string getOtherData() const { return other_data; }

private:
	std::string other_data ;
};

typedef std::unique_ptr<Base> BasePtr ;

int main()
{
	// raw pointer vs smart pointer ->
	//	raw requires manual memory management
	//  smart doesn't.
	// If your compiler doesn't have unique_ptr yet,
	// use shared_ptr.
	std::vector<Base*> raw_vec ;              // vector of raw pointers
	std::vector<BasePtr> unique_vec ;         // vector of unique pointers

	unique_vec.emplace_back(new Derived_1) ;
	unique_vec.emplace_back(new Derived_2) ;

	// if your compiler doesn't support emplace_back, use
	// unique_vec.push_back(BasePtr(newDerived_1)) ;
	// unique_vec.push_back(BasePtr(newDerived_2)) ;

	raw_vec.emplace_back(new Derived_1) ;
	raw_vec.emplace_back(new Derived_2) ;


	std::cout << "name() for raw_vec:\n" ;
	for ( auto i = raw_vec.begin();  i != raw_vec.end(); ++i )
		std::cout << (*i)->name() << '\n' ;

	std::cout << "\nname() for unique_vec:\n" ;
	for ( auto i = unique_vec.begin(); i != unique_vec.end(); ++i )
		std::cout << i->get()->name() << '\n' ;


	// Now we know for certain that each vector contains an object of type
	// Derived_1 in the first element.  This is how we access it
	// when we need Derived_1 behavior.

	Derived_1* rawPtr = static_cast<Derived_1*>(raw_vec[0]) ;
	Derived_1* uniPtr = static_cast<Derived_1*>(unique_vec[0].get()) ;

	rawPtr->setAddedData(59) ;
	uniPtr->setAddedData(100) ;

	std::cout << "\nRaw: " << rawPtr->getAddedData() << '\n' ;
	std::cout << "\nUni: " << uniPtr->getAddedData() << '\n' ;


	// And we know for certain that each vector contains an object of type
	// Derived_1 in the second, but suppose we didn't.  Suppose we needed to
	// iterate through all of the elements in each vector and print out the other
	// data stored in Derived_2 objects (granted, it's just an empty string,
	// but let's verify they're empty!) And we'll pretend for the moment we don't
	// know which elements are which type.

	std::cout << "\n\nDerived_2 for raw vec.\n" ;
	for ( unsigned i = 0 ; i != raw_vec.size() ;  ++i )
	{
		Derived_2* ptr = dynamic_cast<Derived_2*>(raw_vec[i]) ;

		if ( ptr )
		{
			std::cout << "Element " << i << " otherData length = " 
			          << ptr->getOtherData().length() << '\n' ;
		}
	}

	std::cout << "\nDerived_2 for unique_vec.\n" ;
	for ( unsigned i = 0 ; i != unique_vec.size();  ++i )
	{
		Derived_2* ptr = dynamic_cast<Derived_2*>(unique_vec[i].get()) ;

		if ( ptr )
		{
			std::cout << "Element " << i << " otherData length = " 
			          << ptr->getOtherData().length() << '\n' ;
		}
	}

	// Now, let's get rid of the first element of each vector.
	// for the raw vector we need to manually delete the object.
	delete raw_vec[0] ;
	raw_vec.erase(raw_vec.begin());

	// for the unique vector:
	unique_vec.erase(unique_vec.begin()) ;

	// And finally when we're done with the vectors, you just manually
	// destroy all of the objects in raw_vec:
	for ( auto i = raw_vec.begin(); i != raw_vec.end(); ++i )
		delete *i ;

	// while for the unique vector:

	// Yeah, that's right -- nothing.
}
Thank you so much! I just got up, but I've read through the code you posted, and I should be able to use it to figure out everything I need!

I'll start trying it in a bit.

Thanks again for all the trouble!


EDIT: I have another question -

Is there anyway to get the value of a variable like other_data in Derived_2 without a function to return it?

What if I have say, 50 child classes? Do I have to have a separate type cast for each class? Is there any better way?
Last edited on
Topic archived. No new replies allowed.