Am I using this vector wrong?

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

class Object
{
protected:
	std::string name;
	int id;
	int value;


public:
	~Object()
	{

	}

	virtual void Display()
	{

	}

};

class Weapon : public Object
{
private:
	int damage;
	float speed;


public:
	Weapon(std::string newName, int newValue, int newDamage, float newSpeed)
	{
		name = newName;
		value = newValue;
		damage = newDamage;
		speed = newSpeed;
	}

	~Weapon()
	{
	}

	void Display() override
	{
		std::cout << "Name: " << name << std::endl;
		std::cout << "Value: " << value << std::endl;
		std::cout << "Damage: " << damage << std::endl;
		std::cout << "Speed: " << speed << std::endl;

	}

};

int main()
{
	std::vector<Object> inventory;

	Weapon BronzeDagger("Bronze Dagger", 5, 1, 1);

	inventory.push_back(BronzeDagger);

	for(int i = 0; i < inventory.size(); i++)
	{
		inventory[i].Display();
	}

	

	std::cin.get();

	return 0;
}


Not sure what I'm doing wrong. It doesn't display anything. It's acting like the Weapon I made is only an Object.
> It's acting like the Weapon I made is only an Object.
Exactly.
You are storing `Object' objects std::vector<Object> inventory;
> It doesn't display anything.

The derived class object is getting sliced to a base class object; to avoid slicing, use either pointer or reference semantics.

For instance:

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
#include <iostream>
#include <string>
#include <vector>
#include <memory> // **** added

class Object
{
protected:
	std::string name;
	int id;
	int value;


public:
	virtual ~Object() // **** needs to be virtual
	{
	}

	virtual void Display() const // made const-correct
	{

	}

};

class Weapon : public Object
{
private:
	int damage;
	float speed;


public:
	Weapon(std::string newName, int newValue, int newDamage, float newSpeed)
	{
		name = newName;
		value = newValue;
		damage = newDamage;
		speed = newSpeed;
	}

        /****
	~Weapon() // **** implicitly overridden
	{
	}
	****/

	void Display() const override // ****
	{
		std::cout << "Name: " << name << std::endl;
		std::cout << "Value: " << value << std::endl;
		std::cout << "Damage: " << damage << std::endl;
		std::cout << "Speed: " << speed << std::endl;

	}

};

int main()
{
	std::vector< std::shared_ptr<Object> > inventory; // modified

	//Weapon BronzeDagger("Bronze Dagger", 5, 1, 1); // ****
	//inventory.push_back(BronzeDagger); // **** modified
	inventory.push_back( std::make_shared<Weapon>( "Bronze Dagger", 5, 1, 1 ) ) ; // ****
	inventory.push_back( std::make_shared<Weapon>( "Golden Sword", 500, 10, 2 ) ) ; // ****

	// for(int i = 0; i < inventory.size(); i++) // ****
	for( auto p : inventory )
	{
		//inventory[i].Display(); // ****
		p->Display();
                std::cout << '\n' ;
	}
}


http://ideone.com/kYdGFh


Consider following lines:
1
2
3
Object obj;
obj = BronzeDagger;
obj.display();
It will display nothing, because it is Object type! Only Object firlds gets copied, virtual table pointing to Object call and other...

So will vector of objects do.
Last edited on
Change std::vector<Object> inventory;
to
std::vector<Weapon> inventory;

Hope this is what ne555 meant.,
Hope this is what ne555 meant.,
Nope, consider you have two classes "Armor" and "Weapon" derived from "Object", and want to store them in single container. If you change container type to vector<Weapon>, you will not be able to store Armor in it.
Vector of automatic pointers is the best solution to this.
Last edited on
Thanks for all the replies. JLB's way is what I was looking for, but what if I wanted to add items statically?

For example, if you kill someone and click a button, their inventory will be added to yours. You can't just declare vector.pushback(std::make_shared<TYPE> every time because you don't know what type it'll be; it could be a Weapon or a Consumable.

Is there another way or am I just using this wrong? Because every item will be from a class derived Object; just with different functions and stats.

Thanks a bunch.
Last edited on
> their inventory will be added to yours
so just move the pointers.
I want to create Objects from a file and then give the objects to different inventories.

For example:

Weapon : public Object;
Consumable : public Object

Weapon BronzeSword;
Weapon IronSword;
Consumable MinorHealth;
Consumable Bread;

And then I can use these objects with their already made stats throughout my program. Maybe I'm missing something because I can't seem to do it with this way..
> And then I can use these objects with their already made stats throughout my program.

Option one: use a vector of non-owning pointers.
Option two: use a vector of (wrapped) references.

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

struct object
{
    virtual ~object() {}
    virtual void display() const = 0 ;
};

struct weapon : object
{
    explicit weapon( std::string n ) : name(n) {}

    virtual void display() const override { std::cout << "weapon: " << name << '\n' ; }

    const std::string name ;
    // ...
};

struct consumable : object
{
    explicit consumable( std::string d ) : desc(d) {}

    virtual void display() const override { std::cout << "consumable: " << desc << '\n' ; }

    const std::string desc ;
    // ...
};


int main()
{
    weapon BronzeSword ( "bronze sword" ) ;
    weapon IronSword ( "iron sword" ) ;
    consumable MinorHealth ( "minor health" ) ;
    consumable Bread ( "bread" ) ;

    {
        std::vector< object* > inventory ; // option one

        inventory.push_back( &BronzeSword ) ;
        inventory.push_back( &IronSword ) ;
        inventory.push_back( &MinorHealth ) ;
        inventory.push_back( &Bread ) ;

        for( auto ptr : inventory ) ptr->display() ;
    }

    std::cout << "\n---------------------------\n\n" ;

    {
        std::vector< std::reference_wrapper<object> > inventory ; // option two

        inventory.push_back( BronzeSword ) ;
        inventory.push_back( IronSword ) ;
        inventory.push_back( MinorHealth ) ;
        inventory.push_back( Bread ) ;

        for( const auto& wrapper : inventory ) wrapper.get().display() ;
    }
}


http://ideone.com/t5eXnj
Thank you so much :) Exactly what I was looking for.

And thanks to everyone else; such a big help!
Quick note, the way to added inventory with the "&" operator didn't work (violation accessing memory), but making the classes pointers using new and adding them worked. Not sure why. But still, thanks!
> the way to added inventory with the "&" operator didn't work

If the address of (or a reference to) the object is taken, and then after the object is destroyed, we try to use the address (or reference) to get to the object, bad things happen.

Just make sure that the object whose address was taken out-lives the vector.

Topic archived. No new replies allowed.