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.