restocking inventory with inheritance

I am trying to write a function that will restock the inventory ( a vector of shared pointer of "Item") when the number of items for a product sold is lower than 10 . Then it will restock (set) the number to 20.

But the bool restockInventory() method is not working.Hope you can look into it.



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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

"item.hpp"

#include <string>
#include <iostream>

using namespace std;

class Item
{
protected:
	string name_;
	double price_;
	int num_;
public:
	Item() = default;
	Item(string n, double p, int num) : name_(n), price_(p), num_(num) {};
	void to_string()
	{
		cout << "Name: " << name_ << "Price: " << price_ << endl;
	}
	virtual string getName() { return name_; }
	virtual int getNum() { return num_; }
	virtual void setNum(int n) { num_ = n; }
	virtual void dispenseItem() = 0;
	virtual ~Item() {}

};

class Phone : public Item
{
public:
	Phone(string n, double p, int num) : Item(n, p, num) {};
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }
	virtual bool activate() = 0;
	virtual ~Phone() {}
};

class AndroidPhone : public Phone
{
public:
	AndroidPhone(string n, double p, int num) : Phone(n, p, num) {};
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }
	bool activate() override { cout << "Android phone activated\n"; return true; }
	void dispenseItem() override { cout << "Dispensing " << name_ << "from kiosk.\n"; }
	//DEF_BRANDNAME(iphoneT)
};

class iPhone : public Phone
{
public:
	iPhone(string n, double p, int num) : Phone(n, p, num) {};
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }
	bool activate() override { cout << "iPhone activated\n"; return true; }
	void dispenseItem() override { cout << "Dispensing " << name_ << "from kiosk.\n"; }
};

class Case : public Item
{
public:
	Case() = default;
	Case(string n, double p, int num) : Item(n, p, num) {};
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }

};

class AndroidPhoneCase : public Case
{
protected:
	double num_;
public:
	//AndroidPhoneCase(string n, double p) : Case(n, p) {};
	AndroidPhoneCase(string n, double p, int num) : Case(n, p, num) {};
	/*AndroidPhoneCase(string n, double p) 
	{ 
		Item::name_ = n;
		Item::price_ = p;
	}*/
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }
	void dispenseItem() override { cout << "Dispensing " << name_ << "from kiosk.\n"; }

};

class iPhoneCase : public Case
{
protected:
	double num_;
public:
	iPhoneCase(string n, double p, int num) : Case(n, p, num) {};
	int getNum() override { return num_; }
	void setNum(int n) override { num_ = n; }
	void dispenseItem() override { cout << "Dispensing " << name_ << "from kiosk.\n"; }
};


"PhoneManager.hpp"
#include <vector>
#include <string>
#include <memory>
#include "item.hpp"

using namespace std;


class PhoneManager
{
public:
	// using pointer_type = shared_ptr<Item>;
	typedef shared_ptr<Item> pointer_type;
	//typedef shared_ptr<Phone> pointer_type_Phone;
	//typedef shared_ptr<Case> pointer_type_Case;
	typedef enum { iphoneT = 0, AndroidT, iPhoneCaseT, AndroidCaseT };
public:
	vector<pointer_type> v;
	static int numItemSize_;
public:
	PhoneManager();		// create a fully stocked kiosk
						// purchase item will randomly choose an item from the vector and remove it 
						// notify that this item was purchased
	bool purchaseItem();
	// returns a vector with the amount left of each type `
	vector<int> doInventory();
	// if the server person come in, restock the kiosk full
	bool restockInventory(vector<PhoneManager::pointer_type> &);

};




"PhoneManager.cpp"
// Where to put the definitions of the phone manager functions
#include <memory>
#include <iostream>
#include <string>
#include <vector>
#include "PhoneManager.hpp"

using namespace std;

// define the static member property outside the class definition
int PhoneManager::numItemSize_ = 20; // always place in a .cpp

// populate the kiosk with 
PhoneManager::PhoneManager()
{
	// 20
	for (unsigned int i = 0; i < numItemSize_; ++i)
	{
		v.push_back(make_shared<iPhone>("iPhoneX", 1500.00, 20));

		// 20
		v.push_back(make_shared<AndroidPhone>("Google Pixel", 1500.00, 20));
		// 20
		v.push_back(make_shared<iPhoneCase>("Otterbox", 50.00, 20));
		// 20
		v.push_back(make_shared<AndroidPhoneCase>("Lifeskin", 75.00, 20));
	}
	

}

vector<int> PhoneManager::doInventory()
{
	vector<int> inventory(4);
	int IPhoneNum = 0;
	int AndroidNum = 0;
	int IPhoneCaseNum = 0;
	int AndroidCaseNum = 0;

	for (unsigned i = 0; i < v.size(); ++i)
	{
		if (dynamic_cast<iPhone*>(v[i].get()) != nullptr)
		{
			IPhoneNum++;
		}
		else if (dynamic_pointer_cast<AndroidPhone>(v[i]))
		{
			AndroidNum++;
		}
		else if (dynamic_pointer_cast<iPhoneCase>(v[i]))
		{
			IPhoneCaseNum++;
		}
		else if (dynamic_pointer_cast<AndroidPhoneCase>(v[i]))
		{
			AndroidCaseNum++;
		}

	}


	inventory.at(0) = IPhoneNum;
	inventory.at(1) = AndroidNum;
	inventory.at(2) = IPhoneCaseNum;
	inventory.at(3) = AndroidCaseNum;
	return inventory;

}


bool PhoneManager::purchaseItem()
{
		if (!v.empty())
		{
			// generator number from 0~100
			int iRemove = rand() % v.size();
			vector<pointer_type>::iterator it = v.begin() + iRemove;

			// if the element inside the vector is a phone, activate it
			if(auto i = dynamic_pointer_cast<Phone>(*it))
			{
				// if the product type is a phone do activate and dispense 
				i->activate();
				i->dispenseItem();
			}

			else if (auto c = dynamic_pointer_cast<Case>(*it))
			{
				// if the product type is a case just do dispense 
				// dispense the item
				c->dispenseItem();
			}
		
			// remove the item from the vector
			// earse the current product which is pointered by iterator
			v.erase(it);
			// it = v.erase(it);
			return true;
		}
		return false;
}

bool PhoneManager::restockInventory(vector<PhoneManager::pointer_type> &v)
{
	if (true)
	{
		for (unsigned i = 0; i < v.size(); ++i)
		{
			if (dynamic_cast<iPhone*>(v[i].get()) != nullptr && v.at(iphoneT)->getNum() < 10)
			{
				v.at(iphoneT)->setNum(20);
			}
			else if (dynamic_pointer_cast<AndroidPhone>(v[i]) && v.at(AndroidT)->getNum() < 10)
			{
				v.at(AndroidT)->setNum(20);
			}
			else if (dynamic_pointer_cast<iPhoneCase>(v[i]) && v.at(iPhoneCaseT)->getNum() < 10)
			{
				v.at(iPhoneCaseT)->setNum(20);
			}
			else if (dynamic_pointer_cast<AndroidPhoneCase>(v[i]) && v.at(AndroidCaseT)->getNum() < 10)
			{
				v.at(AndroidCaseT)->setNum(20);
			}
		}
	}
	else
	{
			return false;
	}


}


"KioskMain.cpp"
// Simulating the phone kiosk
// Luke
// Jan 5, 2018

#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <ctime>
#include "PhoneManager.hpp"

using namespace std;

int main()
{
	// seed the random number generator 
	srand (unsigned(time(NULL)));

	// test the default constructor
	PhoneManager pm;

	vector<int> inventory = pm.doInventory();
	cout << "IPhone, Android, IPhoneCase, AndroidCase: " << endl;
	for (auto x : inventory)
	{
		cout << x << endl;
	}

	// simulate the purchasing of 20 items
	for (int i = 0; i < 40; ++i)
	{
		bool sold = pm.purchaseItem();
		if (sold == false)
		{
			cout << "No items sold " << endl;
		}
	}
	inventory = pm.doInventory();
	cout << "IPhone, Android, IPhoneCase, AndroidCase: " << endl;
	for (auto x : inventory)
	{
		cout << x << endl;
	}


	cout << endl;
	cout << endl;
	
	for (unsigned i = 0; i < inventory.size(); ++i)
	{
		if (inventory[i] < 10)
		{
			pm.restockInventory(pm.v);
			cout << "Product need to be restocked. " << endl;

		}
		else
		{
			cout << "Product does not need to be restocked. " << endl;

		}
	}

	cout << endl;
	inventory = pm.doInventory();
	cout << "IPhone, Android, IPhoneCase, AndroidCase: " << endl;
	for (auto x : inventory)
	{
		cout << x << endl;
	}
	
}

Hi,

But the bool restockInventory() method is not working.Hope you can look into it.


What is not working, tell us, so we don't have to guess :+)

To better make use of polymorphism, consider having a function that has the same name in all the classes, and performs the increment action.That way you don't have to have an else if chain and dynamic casts : both of which are non scale-able. You can have functions declared to take a base class pointer, and populate the containers with derived class pointers, and the compiler will call the correct function.
so I should put bool restockInventory() in all the derived classes, but for the purpose of this exercise I want to have it done through PhoneManager.
PhoneManager::restockInventory can remain, but each of the derived classes should have its own function to avoid the if else chain you have.

Btw, what kind of nonsense is :

1
2
3
4
if (true) {
// .. statements
}
else {return false;}


Did you get a warning about function not returning a value?

You still haven't said where you program is going wrong?
what do u mean ? where do i use this structure:


2
3
4
if (true) {
// .. statements
}
else {return false;}
At line 232 to erase the purchased item from v. I don't think that's right. Shouldn't you just decrement the number of items?

In other parts of the code, you override getNum() and setNum() in all your classes, but the override versions do the same thing as the base versions. So you don't need to override them at all.

You can use [] instead of at() to improve readability. E.g. v[androidT] instead of v.at(androidT) But note that at() checks to ensure that the index is valid while [] does not.

restockInventory seems unnecessarily complex. Why not just something like:
1
2
3
4
5
for (unsigned i=0; i<v.size(); ++i) {
    if (v[i]->getNum() < 10) {
        v[i].setNum(20);
    }
}

Better yet for readability, use a range-based for loop:
1
2
3
4
5
for (auto &item : v) {
    if (item->getNum() < 10) {
        item->setNum(20);
    }
}



@masterinex

What he means is that in code such as
1
2
3
4
5
6
7
8
if(true){
    //this block of code will always run since true is always true
    //some stuff
}
else{
    //this code will never run
    return false;
}

your function will always run the first block (which also has no return statements) and will never run the else block. It's been a long time since I've read other people's code but still I recommend giving variables more descriptive names and if for any reason you can't, then it would never hurt to place comments in your code.
what do u mean ? where do i use this structure:
1
2
3
4
if (true) {
// .. statements
}
else {return false;} 




In PhoneManager::restockInventory, but as dhayden says, that function is overly complex. On reflection, I guess the getnum / setnum functions fit the specification of what I was talking about before. Although the names of those functions are fine, I would argue that they shouldn't be part of the public interface (they could be part of a protected interface though). Instead, consider a functions with the name Sell( Item&). For each derived class, this function would carry out the appropriate action for that particular item. To make polymorphism work, one needs one of the following : lvalue reference, smart pointer, raw pointer(prefer not). To have a container of references, one needs to use std::reference_wrapper. For smart pointers, I would recommend a std::unique_ptr here, so you would need to read up about using std::move. shared_ptr isn't appropriate here, who is the ownership being shared with?

Another thing is that if one has get / set functions for each member, the class might as well be a plain struct with just public members. Instead think about what is actually happening to the object: in this case it's easy we are selling it, hence the function name Sell . But it is good to have the get / set functions as protected access. The fact that these are functions make the code stronger. For example, if a get/set function changes where it acquires/puts it's value from (say a file, or SQL DB across a network), then we can change just that function, not everywhere that function is called.

With OOP / polymorphism , one of the goals is to make the code scalable, in other words, one should be able to add new derived classes without having to change all the other code to suit. So that is why naming of functions is important. If one has dynamic_cast and / or an else if chain, it usually means the design is wrong, often because one doesn't understand how a derived pointer/ reference is a valid base class pointer /reference.

Also, consider having a class for the inventory itself. At the moment it is a vector<int> in main, But PhoneManager has a public vector of shared_ptr and the restocking function is PhoneManager. This is confusing. Maybe rename PhoneManager to InventoryManager? Make the vector private. You shouldn't need inventory vector in main.

Each of your derived classes has protected data, this is bad for a couple of reasons: Protected data is just as bad as public data; there is no need to have the same member in each derived class. If you do, then that member should be pushed up the inheritance as high as possible, but it still has to make sense. Derived classes should only have members that specialise it from it's base class. Make the inheritance work for you.

At the moment you have these separate variables: Item::num_ ; AndroidPhoneCase::num_ ; IPhoneCase::num_ . This might the heart of your problem: You set the value of num_ but it is referring to AndroidPhoneCase::num_ not Item::num_ for example.

This code emits a warning about type mismatch:
for (unsigned i = 0; i < inventory.size(); ++i)

The size functions return a type of std::size_t (the largest unsigned type the system has) so you should have:
for (std::size_t i = 0; i < inventory.size(); ++i)

This at least avoids the implicit cast from unsigned long long to unsigned .

But as dhayden says , a range based for loop is better. There is another form which is even safer:

1
2
3
4
for (auto&& item : inventory) // auto&& is a forward reference, the safest - does lvalue, rvalue, const, non const
{
  // do something with item
}


You could use it for a print function like this:

1
2
3
4
5
6
Print(const Inventory& TheInventory) {
   for (auto&& item : TheInventory) {
       std::cout << item.getAValue() << "\n";
   }

}


Even better, overload the Item operator<< , so you can do this:

1
2
3
4
5
6
Print(const Inventory& TheInventory) {
   for (auto&& item : TheInventory) {
       std::cout << item << "\n";
   }

}


C++17 has structured bindings, you could Google that if you want.

Good Luck !!

Edit:

One more thing:

Don't include the name of the base class in the name of the derived class:

class AndroidPhoneCase : public Case

It is unnecessary clutter that gets out of hand, imagine :

class AndroidPhoneChargerCableAdapterUsb

Instead:

1
2
class Phone;
class Android : public Phone;


This brings up another topic: avoid massive inheritance trees. But that is another story involving templates.
Last edited on
Topic archived. No new replies allowed.