How to output a map from a class with operator overloading

Pages: 1234
So im trying to output the contents of a map from the class and i obviously have to overload the << operator to do so but i cant seem to figure out what im dong wrong. I have this in my container class:

1
2
3
4
5
6
7
8
9
    std::ostream& operator<< (std::ostream& os)
    {
        for (auto & i : mContainer)
        {
            os << i.first;
        }

        return os;
    }


What am i doing wrong here? I've been searching for hours and watching videos but i cant seem to apply the right fix to this and I give up on searching.


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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//============================================================================
// Name             : Console Text Shooter
// Author           : Chay Hawk
// Version          : 0.1.4
// Version Date     : November 1st 2022 @ 1:18 PM
// Date Created     : October 31st 2022 @ 12:28 PM
// Lines of Code    : 165
// Description      : 
//============================================================================

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <utility>

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::map;
using std::pair;
using std::iterator;
using std::make_pair;

class Character
{
public:
    Character(const string& name, int health) : mName(name), mHealth(health)
    {}

    string GetName() const { return mName; }
    int GetHealth() const { return mHealth; }

private:
    string mName{ "Character Name" };
    int mHealth{ 100 };
};

class Item
{
public:
    Item(const string& name, int size) : mName(name), mSize(size)
    {}
    Item() = default;

    string GetName() const { return mName; }

private:
    string mName{ "Weapon Name" };
    int mSize{ 0 }; //Space taken up in container
};

bool operator< (const Item& lhs, const Item& rhs)
{
    return lhs.GetName() < rhs.GetName();
}

//std::ostream& operator<< (std::ostream os, const Item& item)
//{
//    os << item.GetName();
//
//    return os;
//}

//Should create a projectile weapon class and a melee weapon class that inherit from Weapon.

class Weapon : public Item
{
public:
    Weapon
    (
        const string& name,
        int size, const int magazineMaxSize,
        const int ammoReserveMaxSize,
        int magazineCount,
        int ammoReserveCount)
        : Item{ name, size },
        mMagazineMaxSize(magazineMaxSize),
        mAmmoReserveMaxSize(ammoReserveMaxSize),
        mMagazineCount(magazineCount),
        mAmmoReserveCount(ammoReserveCount)
    {}

    int GetMagazineMaxSize() const { return mMagazineMaxSize; }
    int GetAmmoReserveMaxSize() const { return mAmmoReserveMaxSize; }
    int GetMagazineCount() const { return mMagazineCount; }
    int GetAmmoReserveCount() const { return mAmmoReserveCount; }

    //NOT WORKING
    void Reload()
    {
        //We want to reload the magazine and get ammo from the reserve count so we need
        //to make sure the reserve has enough to reload and if it does then add that 
        //amount to the magazine

        int sum = mMagazineMaxSize - mMagazineCount;

        if (mAmmoReserveCount > 0)
        {
            //If even 1 bullet is missing
            if (mMagazineCount < mMagazineMaxSize)
            {
                //If we have more reserve ammo than the max size of the magazine.
                if (mAmmoReserveCount > mMagazineMaxSize)
                {
                    mMagazineCount = mMagazineMaxSize;
                    cout << "DEBUG - SUM: " << sum << '\n';
                    mAmmoReserveCount -= sum;
                }
                //If we dont then execute this code
                else
                {
                    mMagazineCount += mAmmoReserveCount;
                    mAmmoReserveCount = 0;
                }
            }
        }
        else
        {
            //Code not executing
            cout << "Out of ammo for the " << GetName() << "!\n";
        }
    }

    void Fire()
    {
        //For this we need to make sure the magazine has enough ammo in it to fire first, then if it does
        //allow it to fire, then once the ammo reaches 0, then reload.

        if (mMagazineCount > 0)
        {
            mMagazineCount--;
        }
        else
        {
            cout << "Reloading!\n";
            Reload();
        }
    }

private:
    const int mMagazineMaxSize{ 0 };
    const int mAmmoReserveMaxSize{ 0 };
    int mMagazineCount{ 0 };
    int mAmmoReserveCount{ 0 };
};

class Container
{
public:
    Container(const string& name, int containerSize) : mName(name), mContainerSize(containerSize)
    {}

    void AddItem(Item& item, int amount)
    {
        mContainer.insert(pair<Item, int>(item, amount));
    }

    void RemoveItem(Item& item)
    {
        
    }

    void DecrementAmountHeld()
    {

    }

    void IncrementAmountHeld()
    {

    }

    void DisplayContents()
    {
        for (const auto& i : mContainer)
        {
            cout << i.first;
        }
    }

    std::ostream& operator<< (std::ostream& os)
    {
        for (auto & i : mContainer)
        {
            os << i.first;
        }

        return os;
    }

private:
    string mName{ "Container Name" };
    int mContainerSize{ 0 };
    map<Item, int> mContainer;
};

int main()
{
    Container PlayerInventory("Player Inventory", 50);

    Weapon Rifle("Rifle", 4, 30, 999, 3, 6);
    Weapon Handgun("Handgun", 2, 8, 999, 8, 16);
    Weapon Shotgun("Shotgun", 5, 8, 999, 8, 24);

    cout << "Magazine Count: " << Rifle.GetMagazineCount() << '\n';
    cout << "Ammo Reserve Count: " << Rifle.GetAmmoReserveCount() << '\n';
    cout << "Magazine Max Size: " << Rifle.GetMagazineMaxSize() << '\n';

    //Rifle.Reload();

    Rifle.Fire();
    Rifle.Fire();
    Rifle.Fire();
    Rifle.Fire();

    cout << "Magazine Count: " << Rifle.GetMagazineCount() << '\n';
    cout << "Ammo Reserve Count: " << Rifle.GetAmmoReserveCount() << '\n';
    cout << "Magazine Max Size: " << Rifle.GetMagazineMaxSize() << '\n';

    PlayerInventory.AddItem(Rifle, 1);
    PlayerInventory.AddItem(Handgun, 1);
    PlayerInventory.AddItem(Shotgun, 1);

    cout << "DISPLAY INVENTORY\n\n";

    PlayerInventory.DisplayContents();

    cout << '\n';

    PlayerInventory.RemoveItem(Shotgun);

    PlayerInventory.DisplayContents();
}
i obviously have to overload the << operator

Where did you overload the operator<< for the item class?

Im a bit confused here, i need to output the map, but im unsure if i create an overload for the map, the item class or the container class. since map is part of the container class i tried to do it for that, but since the map is of type Item, I should overload inside that class? im so confused! :(
I think i got it:

Im still a bit confised, so I overload for th class that the container uses correct?

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//============================================================================
// Name             : Console Text Shooter
// Author           : Chay Hawk
// Version          : 0.1.4
// Version Date     : November 1st 2022 @ 1:18 PM
// Date Created     : October 31st 2022 @ 12:28 PM
// Lines of Code    : 165
// Description      : 
//============================================================================

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <utility>

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::map;
using std::pair;
using std::iterator;
using std::make_pair;

class Character
{
public:
    Character(const string& name, int health) : mName(name), mHealth(health)
    {}

    string GetName() const { return mName; }
    int GetHealth() const { return mHealth; }

private:
    string mName{ "Character Name" };
    int mHealth{ 100 };
};

class Item
{
public:
    Item(const string& name, int size) : mName(name), mSize(size)
    {}
    Item() = default;

    string GetName() const { return mName; }

private:
    string mName{ "Weapon Name" };
    int mSize{ 0 }; //Space taken up in container
};

bool operator< (const Item& lhs, const Item& rhs)
{
    return lhs.GetName() < rhs.GetName();
}

std::ostream& operator<< (std::ostream& os, const Item& item)
{
    os << item.GetName();

    return os;
}

//std::ostream& operator<< (std::ostream os, const Item& item)
//{
//    os << item.GetName();
//
//    return os;
//}

//Should create a projectile weapon class and a melee weapon class that inherit from Weapon.

class Weapon : public Item
{
public:
    Weapon
    (
        const string& name,
        int size, const int magazineMaxSize,
        const int ammoReserveMaxSize,
        int magazineCount,
        int ammoReserveCount)
        : Item{ name, size },
        mMagazineMaxSize(magazineMaxSize),
        mAmmoReserveMaxSize(ammoReserveMaxSize),
        mMagazineCount(magazineCount),
        mAmmoReserveCount(ammoReserveCount)
    {}

    int GetMagazineMaxSize() const { return mMagazineMaxSize; }
    int GetAmmoReserveMaxSize() const { return mAmmoReserveMaxSize; }
    int GetMagazineCount() const { return mMagazineCount; }
    int GetAmmoReserveCount() const { return mAmmoReserveCount; }

    //NOT WORKING
    void Reload()
    {
        //We want to reload the magazine and get ammo from the reserve count so we need
        //to make sure the reserve has enough to reload and if it does then add that 
        //amount to the magazine

        int sum = mMagazineMaxSize - mMagazineCount;

        if (mAmmoReserveCount > 0)
        {
            //If even 1 bullet is missing
            if (mMagazineCount < mMagazineMaxSize)
            {
                //If we have more reserve ammo than the max size of the magazine.
                if (mAmmoReserveCount > mMagazineMaxSize)
                {
                    mMagazineCount = mMagazineMaxSize;
                    cout << "DEBUG - SUM: " << sum << '\n';
                    mAmmoReserveCount -= sum;
                }
                //If we dont then execute this code
                else
                {
                    mMagazineCount += mAmmoReserveCount;
                    mAmmoReserveCount = 0;
                }
            }
        }
        else
        {
            //Code not executing
            cout << "Out of ammo for the " << GetName() << "!\n";
        }
    }

    void Fire()
    {
        //For this we need to make sure the magazine has enough ammo in it to fire first, then if it does
        //allow it to fire, then once the ammo reaches 0, then reload.

        if (mMagazineCount > 0)
        {
            mMagazineCount--;
        }
        else
        {
            cout << "Reloading!\n";
            Reload();
        }
    }

private:
    const int mMagazineMaxSize{ 0 };
    const int mAmmoReserveMaxSize{ 0 };
    int mMagazineCount{ 0 };
    int mAmmoReserveCount{ 0 };
};

class Container
{
public:
    Container(const string& name, int containerSize) : mName(name), mContainerSize(containerSize)
    {}

    void AddItem(Item& item, int amount)
    {
        mContainer.insert(pair<Item, int>(item, amount));
    }

    void RemoveItem(Item& item)
    {
        
    }

    void DecrementAmountHeld()
    {

    }

    void IncrementAmountHeld()
    {

    }

    void DisplayContents()
    {
        for (const auto& i : mContainer)
        {
            cout << i.first;
        }
    }

private:
    string mName{ "Container Name" };
    int mContainerSize{ 0 };
    map<Item, int> mContainer;
};

int main()
{
    Container PlayerInventory("Player Inventory", 50);

    Weapon Rifle("Rifle", 4, 30, 999, 3, 6);
    Weapon Handgun("Handgun", 2, 8, 999, 8, 16);
    Weapon Shotgun("Shotgun", 5, 8, 999, 8, 24);

    cout << "Magazine Count: " << Rifle.GetMagazineCount() << '\n';
    cout << "Ammo Reserve Count: " << Rifle.GetAmmoReserveCount() << '\n';
    cout << "Magazine Max Size: " << Rifle.GetMagazineMaxSize() << '\n';

    //Rifle.Reload();

    Rifle.Fire();
    Rifle.Fire();
    Rifle.Fire();
    Rifle.Fire();

    cout << "Magazine Count: " << Rifle.GetMagazineCount() << '\n';
    cout << "Ammo Reserve Count: " << Rifle.GetAmmoReserveCount() << '\n';
    cout << "Magazine Max Size: " << Rifle.GetMagazineMaxSize() << '\n';

    PlayerInventory.AddItem(Rifle, 1);
    PlayerInventory.AddItem(Handgun, 1);
    PlayerInventory.AddItem(Shotgun, 1);

    cout << "DISPLAY INVENTORY\n\n";

    PlayerInventory.DisplayContents();

    cout << '\n';

    PlayerInventory.RemoveItem(Shotgun);

    PlayerInventory.DisplayContents();
}
Last edited on
Since "first" is an Item you need an overload of the Item class.

Look closely at the error messages, they should tell you what is wrong.

Fix the first error, recompile, repeat until all errors/warnings are resolved.



I got it working now, but now i cant erase an element from the map. do i need to make an overload of that too? I mad a map in main and did the erase method and it worked but doing it the same way in the class gives me an error... very frustrating

1
2
3
4
void RemoveItem(Item& item)
    {
        mContainer.erase(item.GetName());
    }


I assume since im trying to get a class member then it does but thats gotta be annoyign to define every single behaviour for the map in the class D:
Last edited on
gotta be annoying to define every single behavior for the map in the class

If you want to avoid that, then you should take advantage of inheritance.
 
class Container : public map<Item, int>


BTW: It's not necessary to keep track of the number of elements in a container.
std::map and most other containers keep track of the number of elements for you.
https://cplusplus.com/reference/map/map/size/
Last edited on
It should be
1
2
3
4
void RemoveItem(Item& item)
{
    mContainer.erase(item);
}

because the key of the map is an Item not a string.
I was able to figure that out with some trial and error, but what if i wanted to select an item from the map to delete based on its element and not the key? is that possible? Here is my current code just in case its needed.

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//============================================================================
// Name             : Console Text Shooter
// Author           : Chay Hawk
// Version          : 0.1.5
// Version Date     : December 14th 2022 @ 2:06 PM
// Date Created     : October 31st 2022 @ 12:28 PM
// Lines of Code    : 273
// Description      : 
//============================================================================

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <utility>

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::map;
using std::pair;
using std::iterator;
using std::make_pair;

class Character
{
public:
    Character(const string& name, int health) : mName(name), mHealth(health)
    {}

    string GetName() const { return mName; }
    int GetHealth() const { return mHealth; }

private:
    string mName{ "Character Name" };
    int mHealth{ 100 };
};

class Item
{
public:
    Item(const string& name, int size, int maxStackSize) : mName(name), mSize(size), mMaxStackSize(maxStackSize)
    {}
    Item() = default;

    string GetName() const { return mName; }
    int GetMaxStackSize() const { return mMaxStackSize; }

private:
    string mName{ "Weapon Name" };
    int mSize{ 0 }; //Space taken up in container
    const int mMaxStackSize{ 0 }; //Max stack size for all items.
};

bool operator< (const Item& lhs, const Item& rhs)
{
    return lhs.GetName() < rhs.GetName();
}

std::ostream& operator<< (std::ostream& os, const Item& item)
{
    os << item.GetName();
    return os;
}

//Should create a projectile weapon class and a melee weapon class that inherit from Weapon.

class Weapon : public Item
{
public:
    Weapon
    (
        const string& name,
        int size, 
        const int maxStackSize,
        const int magazineMaxSize,
        const int ammoReserveMaxSize,
        int magazineCount,
        int ammoReserveCount)
        : Item{ name, size, maxStackSize },
        mMagazineMaxSize(magazineMaxSize),
        mAmmoReserveMaxSize(ammoReserveMaxSize),
        mMagazineCount(magazineCount),
        mAmmoReserveCount(ammoReserveCount)
    {}

    int GetMagazineMaxSize() const { return mMagazineMaxSize; }
    int GetAmmoReserveMaxSize() const { return mAmmoReserveMaxSize; }
    int GetMagazineCount() const { return mMagazineCount; }
    int GetAmmoReserveCount() const { return mAmmoReserveCount; }

    //This may need some revision but I believe its working correctly.
    void Reload()
    {
        if (mAmmoReserveCount > 0)
        {
            int ammoNeeded = mMagazineMaxSize - mMagazineCount;
            cout << ammoNeeded << "\n\n";

            if (mAmmoReserveCount >= ammoNeeded)
            {
                cout << "DEBUG: Weapon reloaded\n\n";
                mAmmoReserveCount -= ammoNeeded;
                mMagazineCount = mMagazineMaxSize;
            }
            else
            {
                mMagazineCount += mAmmoReserveCount;
                mAmmoReserveCount = 0;
            }
        }
        else
        {
            cout << "You have no ammo left!\n\n";
        }
    }

    void Fire()
    {
        //For this we need to make sure the magazine has enough ammo in it to fire first, then if it does
        //allow it to fire, then once the ammo reaches 0, then reload.

        if (mMagazineCount > 0)
        {
            mMagazineCount--;
            cout << mMagazineCount << " rounds left\n\n";
        }
        else
        {
            cout << "Out of ammo, Reload!\n";
        }

    }

private:
    const int mMagazineMaxSize{ 0 };
    const int mAmmoReserveMaxSize{ 0 };
    int mMagazineCount{ 0 };
    int mAmmoReserveCount{ 0 };
};

class Container
{
public:
    Container(const string& name, int containerSize) : mName(name), mContainerSize(containerSize)
    {}

    void AddItem(Item& item, int amount)
    {
        if (amount <= item.GetMaxStackSize())
        {
            mContainer.insert(pair<Item, int>(item, amount));
        }
        else if(amount > item.GetMaxStackSize())
        {
            cout << "DEBUG: Item " << item.GetName() << " has exceeded the max stack size, resizing...\n";
            mContainer.insert(pair<Item, int>(item, item.GetMaxStackSize()));
        }
    }

    //Remove item by key
    void RemoveItem(Item& item)
    {
        mContainer.erase(item);
    }

    //Remove item by element
    void RemoveItem(int element)
    {
        //mContainer.erase(element);
    }

    void DecrementAmountHeld()
    {

    }

    void IncrementAmountHeld()
    {

    }

    void DisplayContents()
    {
        int enumerate{ 1 };

        if (mContainer.empty())
        {
            cout << "Inventory is empty\n\n";
        }
        else if (mContainer.size() > 0)
        {
            for (const auto& i : mContainer)
            {
                cout << enumerate++ << ") " <<  i.first << " x " << i.second << "\n";
            }
        }
        cout << '\n';
    }

    int GetSize() const
    {
        return mContainer.size();
    }

private:
    string mName{ "Container Name" };
    int mContainerSize{ 0 };
    map<Item, int> mContainer;
};

int main()
{
    Container PlayerInventory("Player Inventory", 50);

    Item NineMMAmmo("9mm Round", 1, 999);
    Item FiveFiveSixAmmo("5.56mm Round", 1, 999);
    Item ShotgunSlugAmmo("Shotgun Slug Round", 1, 999);

    Weapon Rifle("Rifle", 4, 1, 30, 9999, 7, 50);
    Weapon Handgun("Handgun", 2, 1, 8, 999, 8, 16);
    Weapon Shotgun("Shotgun", 5, 1, 8, 999, 8, 24);

    cout << "Rifle Reserve Ammo: " << Rifle.GetAmmoReserveCount() << "\n";
    cout << "Rifle Magazine Size: " << Rifle.GetMagazineCount() << "\n\n";

    Rifle.Reload();

    cout << "Rifle Reserve Ammo: " << Rifle.GetAmmoReserveCount() << "\n";
    cout << "Rifle Magazine Size: " << Rifle.GetMagazineCount() << "\n\n";

    //Rifle.Fire();
    //Rifle.Fire();
    //Rifle.Fire();

    Rifle.Reload();

    cout << "Rifle Reserve Ammo: " << Rifle.GetAmmoReserveCount() << "\n";
    cout << "Rifle Magazine Size: " << Rifle.GetMagazineCount() << "\n\n";

    //TESTING

    cout << "TESTING\n\n";

    PlayerInventory.AddItem(Rifle, 1);
    PlayerInventory.AddItem(Handgun, 3);
    PlayerInventory.AddItem(Shotgun, 2);
    PlayerInventory.AddItem(ShotgunSlugAmmo, 500);
    PlayerInventory.AddItem(NineMMAmmo, 200);
    PlayerInventory.AddItem(FiveFiveSixAmmo, 856);

    cout << "\n\nInventory Size: " << PlayerInventory.GetSize() << " items.\n\n";

    int choice{ 0 };
    int chooseItem{ 0 };

    while (choice != 4)
    {
        cout << "1) Weapon Testing\n";
        cout << "2) Remove Item\n";
        cout << "3) Show Inventory\n";
        cout << "4) Quit\n";

        cout << ">";
        cin >> choice;

        cout << '\n';

        switch (choice)
        {
            case 1:
                cout << "Which weapon would you like to test?\n\n";

                PlayerInventory.DisplayContents();

                cin >> chooseItem;

                break;

            case 2:
                cout << "Which item would you like to remove?\n\n";

                PlayerInventory.DisplayContents();

                cin >> chooseItem;

                PlayerInventory.RemoveItem(chooseItem);

                break;

            case 3:

                PlayerInventory.DisplayContents();

                break;

            case 4:

                cout << "Goodbye!";
                return 0;

                break;

            default:
                cout << "You have made an invalid choice\n\n";
        }
    }
}
you can do that with a linear search, but what if multiple keys have the same value ? Keys are unique, but their data isn't.

here is an example:
https://www.geeksforgeeks.org/search-by-value-in-a-map-in-c/
Thanks for the help guys. I'll stick to just keeping it like it is. I hate it because its easier for me to use a vector in some ways but the map is easier in ways the vector isnt, like adding and removing things. Both have pros and cons. Its hard for me to decide which one to use. By the way, is there a program to help with planning out code design? I know about flow charts and diagrams like that, ive mad them before but im wondering if theres a program that can help visualize software and help plan out what code and functions and classes are needed to create it.
Unified Modeling Language (UML) is widely used for that.
https://en.wikipedia.org/wiki/Unified_Modeling_Language#:~:text=The%20Unified%20Modeling%20Language%20(UML,the%20design%20of%20a%20system.

There are some free UML modeling programs around.
different containers exist because they do have different pros & cons, yes. A basic review of data structures & a bit of understanding the c++ flavors offered is useful.
even without the formal DS&A class, a quick web search nets you some good starting points that will go a very long way:
https://www.hackerearth.com/practice/notes/c-stls-when-to-use-which-stl/
and there are other sites with flowcharts to decide which to use or other features listed.

what is missing from the formal class are the other tools -- like a lazy delete -- that can pull one container towards another in terms of fixing a weakness. A sorted vector for example, removing the first element and shifting all the others is expensive, but marking it as deleted to deal with later (by having your sort move deleted ones to the back to reclaim or remove) works naturally, when you re-sort, it fixes itself. That is just one example of 'correcting' a weakness; you can do all kinds of stuff like this with all of them.

Ive lost track, what do you want to be able to do, remove by value without having the keys?
Last edited on
Yeah so basically, if the player wants to be able to remove an item from their inventory, I have the interface setup so the inventory is enumerated when its output, and usually in a vector i can output it and enumerate it and the player can select a number and i can perform an erase operation by taking the number entered -1 and removing that element

so heres a small example i put together of what id like to be able to do with the map if possible:

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

using std::vector;
using std::cout;
using std::cin;

int main()
{
    vector<int> vect;

    vect.push_back(5);
    vect.push_back(3);
    vect.push_back(9);
    vect.push_back(23);
    vect.push_back(40);

    int choice{ 0 };
    int enumerate{ 1 };

    for (auto& i : vect)
    {
        cout << enumerate++ << ") " << i << "\n";
    }

    cout << "\nRemove what element?\n\n";

    cout << ">";
    cin >> choice;

    vect.erase(std::remove(vect.begin(), vect.end(), vect[choice -1]), vect.end());

    enumerate = 1;

    for (auto& i : vect)
    {
        cout << enumerate++ << ") " << i << "\n";
    }
}
but what if i wanted to select an item from the map to delete based on its element and not the key?


Another idea for this to consider (which may or may not be appropriate) is to use an 'inverse map'. This is a multimap which has as its keys the values of the main map and it's values as the keys of the main map. So given a value of the main map, you use the inverse multimap to find the associated key(s).

The disadvantage, of course, is that you now have 2 maps to maintain and to make sure they are in sync.
Note that since C++20 you can code as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <vector>

int main() {
	std::vector vect { 5, 3, 9, 23, 40 };

	for (size_t enumerate {};  auto i : vect)
		std::cout << ++enumerate << ") " << i << "\n";

	size_t choice { };

	std::cout << "\nRemove which element? ";
	std::cin >> choice;

	std::erase(vect, vect[choice - 1]);

	for (size_t enumerate {}; auto i : vect)
		std::cout << ++enumerate << ") " << i << "\n";
}

Last edited on
By the way, is there a program to help with planning out code design? I know about flow charts and diagrams like that, ive mad them before but im wondering if theres a program that can help visualize software and help plan out what code and functions and classes are needed to create it.


Visual Studio comes with a class designer, though you have to install it seperately.
https://pasteboard.co/Ao5BRwqWVzd4.png
https://pasteboard.co/89gPnYoftIGd.png
Just a couple of points re the main code

- L23 using std::iterator. This was deprecated in C++17. Just remove.

Also, std::map has emplace - so you can code:

1
2
//mContainer.insert(pair<Item, int>(item, amount));
mContainer.emplace(item, amount);


L163 - as item is passed by ref and not intended to be changed, then pass by const ref:

1
2
3
void RemoveItem(const Item& item) {
    mContainer.erase(item);
}


L192 - there's no need to check if mContainer is not empty before the range-for:

1
2
3
4
5
6
7
8
9
void DisplayContents() {
    if (mContainer.empty())
        cout << "Inventory is empty\n";
    else
        for (size_t enumerate {}; const auto& i : mContainer)
            cout << ++enumerate << ") " << i.first << " x " << i.second << "\n";

    cout << '\n';
}


L202 - the type of the .size() for a container is size_t, so the return type should be size_t and not int

1
2
3
size_t GetSize() const {
    return mContainer.size();
}


likewise, the type of variables used to store a size (but why store?) should also be of size_t and not int.
Last edited on
Thanks for the replies, I think ill just stick to the map for now, or find a way to use a vector later on. I'll look into the UML stuff as well. But now I have a new problem. So in my program im trying to update the count of the ammo but its not working. I set the ammo stack size as 600 for rifles but it isnt working at all, i made the item class update the count but i think this should be the job of the Container class so theres code from that in there still in the item class and container class. I tried to manually update it in the container class but nothing is working and im stumped cause ive been trying to figure this out for a few hours now. I even re wrote it and still nothing, i think i may have made it worse but idk. The problem is in the Weapon class in the reload function i believe. I'll have to post this in a few posts cause its so big:

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <utility>

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::map;
using std::pair;
using std::iterator;
using std::make_pair;

class Character
{
    public:
        Character(const string& name, int health) : mName(name), mHealth(health)
        {}

        string GetName() const { return mName; }
        int GetHealth() const { return mHealth; }

    private:
        string mName{ "Character Name" };
        int mHealth{ 100 };
};

class Item
{
    public:
        Item(const string& name, int slotsUsed, int currentStackSize, const int maxStackSize) : mName(name), mSlotsUsed(slotsUsed), mCurrentStackSize(currentStackSize), mMaxStackSize(maxStackSize)
        {}
        Item() = default;

        string GetName() const { return mName; }
        int GetCurrentStackSize() const { return mCurrentStackSize; }
        int GetMaxStackSize() const { return mMaxStackSize; }
        int GetSlotsUsed() const { return mSlotsUsed; }

        void IncreaseStackSize(int amount)
        {
            mCurrentStackSize += amount;
        }

        void DecreaseStackSize(int amount)
        {
            mCurrentStackSize -= amount;
        }

        void SetStackSize(int amount)
        {
            mCurrentStackSize = amount;
        }

    private:
        string mName{ "Weapon Name" };
        int mSlotsUsed{ 0 }; //Space taken up in container
        int mCurrentStackSize{ 0 };
        const int mMaxStackSize{ 0 }; //Max stack size for all items.
};

bool operator< (const Item& lhs, const Item& rhs)
{
    return lhs.GetName() < rhs.GetName();
}

std::ostream& operator<< (std::ostream& os, const Item& item)
{
    os << item.GetName();
    return os;
}

//Should create a projectile weapon class and a melee weapon class that inherit from Weapon.

class Weapon : public Item
{
    public:
        Weapon
        (
            const string& name,
            int size, 
            int currentStackSize,
            const int maxStackSize,
            const int magazineMaxSize,
            const int ammoReserveMaxSize,
            int magazine,
            int ammoReserve)
            : Item{ name, size, currentStackSize, maxStackSize },
            mMagazineMaxCapacity(magazineMaxSize),
            mMagazine(magazine)
        {}

        int GetMagazineMaxSize() const { return mMagazineMaxCapacity; }
        int GetCurrentMagazineCount() const { return mMagazine; }

        //This may need some revision but I believe its working correctly.
        void Reload(Item& item)
        {
            //ISSUE - Need to figure out how to subtract ammo from reserve. as of right now
            //When checking inventory, the ammo stays the same even though i subtracted some.

            cout << "DEBUG: STACK SIZE: " << item.GetCurrentStackSize() << "\n\n";
            if (item.GetCurrentStackSize() > 0)
            {
                int ammoNeeded = mMagazineMaxCapacity - mMagazine;
                cout << ammoNeeded << "\n\n";

                if (item.GetCurrentStackSize() >= ammoNeeded)
                {
                    cout << "DEBUG: Weapon reloaded\n\n";
                    item.DecreaseStackSize(ammoNeeded);
                    mMagazine = mMagazineMaxCapacity;
                }
                else
                {
                    mMagazine += item.GetCurrentStackSize();
                    item.SetStackSize(0);
                }
            }
            else
            {
                cout << "You have no ammo left!\n\n";
            }
        }

        void Fire()
        {
            //For this we need to make sure the magazine has enough ammo in it to fire first, then if it does
            //allow it to fire, then once the ammo reaches 0, then reload.

            if (mMagazine > 0)
            {
                mMagazine--;
                cout << mMagazine << " rounds left\n\n";
            }
            else
            {
                cout << "Out of ammo, Reload!\n";
            }

        }

    private:
        const int mMagazineMaxCapacity{ 0 };
        int mMagazine{ 0 };
};

class Container
{
    public:
        Container(const string& name, int containerSize, int amountStored) : mName(name), mContainerSize(containerSize), mAmountStored(amountStored)
        {}

        void AddItem(Item& item)
        {
            if (item.GetCurrentStackSize() <= item.GetMaxStackSize())
            {
                if (item.GetSlotsUsed() > mContainerSize)
                {
                    cout << "You do not have enough room in your inventory for " << item.GetName() << "\n\n";
                }
                else
                {
                    mContainer.insert(pair<Item, int>(item, item.GetCurrentStackSize()));
                }
            }
            else if(item.GetCurrentStackSize() > item.GetMaxStackSize())
            {
                cout << "Cannot pick up item " << item.GetName() << " as it has exceeded the max stack size...\n";
                mContainer.insert(pair<Item, int>(item, item.GetMaxStackSize()));
                mContainerSize -= item.GetSlotsUsed();
            }
        }

        void RemoveItem(const Item& item)
        {
            mContainer.erase(item);
        }

        int GetContainerSize() const { return mContainerSize; }
        int GetAmountStored() const { return mAmountStored; }

        void IncreaseStackSize(Item& item, int amount)
        {
            mContainer[item] = item.IncreaseStackSize(amount);
        }

        void DecreaseStackSize(Item& item, int amount)
        {
            //mCurrentStackSize -= amount;
        }

        void SetStackSize(Item& item, int amount)
        {
            //mCurrentStackSize = amount;
        }
 
        void DisplayContents()
        {
            int enumerate{ 1 };

            cout << "Inventory Slots Left: " << mContainerSize << "\n\n";

            if (mContainer.empty())
            {
                cout << "Inventory is empty\n\n";
            }
            else if (mContainer.size() > 0)
            {
                for (const auto& i : mContainer)
                {
                    cout << enumerate++ << ") " <<  i.first << " x " << i.second << "\n";
                }
            }
            cout << '\n';
        }

        int GetSize() const
        {
            return mContainer.size();
        }

    private:
        string mName{ "Container Name" };
        int mContainerSize{ 0 };
        int mAmountStored{ 0 };
        map<Item, int> mContainer;
};
Last edited on
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
int main()
{
    Container PlayerInventory("Player Inventory", 50, 0);

    Item NineMMAmmo("9mm Round", 1, 120, 9999);
    Item FiveFiveSixAmmo("5.56mm Round", 1, 600, 9999);
    Item ShotgunSlugAmmo("Shotgun Slug Round", 1, 50, 9999);

    cout << "5.56mm Ammo Stack Size: " << FiveFiveSixAmmo.GetCurrentStackSize() << "\n\n";

    Weapon Rifle("Rifle", 4, 1, 1, 30, 9999, 7, FiveFiveSixAmmo.GetCurrentStackSize());
    Weapon Handgun("Handgun", 2, 1, 1, 8, 9999, 8, NineMMAmmo.GetCurrentStackSize());
    Weapon Shotgun("Shotgun", 5, 1, 1, 8, 9999, 8, ShotgunSlugAmmo.GetCurrentStackSize());

    cout << "RIFLE RESERVE SIZE: " << Rifle.GetCurrentStackSize() << "\n\n";

    PlayerInventory.AddItem(Rifle);
    PlayerInventory.AddItem(Handgun);
    PlayerInventory.AddItem(Shotgun);

    PlayerInventory.AddItem(ShotgunSlugAmmo);
    PlayerInventory.AddItem(NineMMAmmo);
    PlayerInventory.AddItem(FiveFiveSixAmmo);

    cout << "RIFLE RESERVE SIZE: " << Rifle.GetCurrentStackSize() << "\n\n";
    cout << "HANDGUN RESERVE SIZE: " << Handgun.GetCurrentStackSize() << "\n\n";
    cout << "SHOTGUN RESERVE SIZE: " << Shotgun.GetCurrentStackSize() << "\n\n";

    int choice{ 0 };
    int chooseItem{ 0 };

    Rifle.Reload(FiveFiveSixAmmo);
    cout << "DEBUG: RIFLE AMMO RESERVE: " << Rifle.GetCurrentStackSize() << "\n\n";

    while (choice != 4)
    {
        cout << "===MAIN MENU===\n\n";

        cout << "1) Weapon Testing\n";
        cout << "2) Remove Item\n";
        cout << "3) Show Inventory\n";
        cout << "4) Quit\n";

        cout << ">";
        cin >> choice;
        string name{ "" };

        cout << '\n';

        switch (choice)
        {
            case 1:
                cout << "Which weapon would you like to test?\n\n";

                PlayerInventory.DisplayContents();

                cin >> chooseItem;

                break;

            case 2:
                cout << "Which item would you like to remove?\n\n";

                PlayerInventory.DisplayContents();

                getline(cin, name);

                break;

            case 3:

                PlayerInventory.DisplayContents();

                break;

            case 4:

                cout << "Goodbye!";
                return 0;

                break;

            default:
                cout << "You have made an invalid choice\n\n";
        }
    }
}
Pages: 1234