Hi,
There are a bunch of things going on here. Realise that "Access a derived class from Base class" is a common misconception.
First up, IMO Sandwich should not inherit from Order. Public inheritance means an "IS A" relationship: a Sandwich is not an Order.
But it is OK for
Cheesesteak
et al to inherit from
Sandwich
because they are sandwiches.
You could do the same for the sides, have a class for each which inherits from
Side
. Same for
Drink
All of
Sandwich
and
Side
and
Drink
could inherit from
Product
Then
Order
could have a
std::vector<Product *> BillItems
as a private variable so we can have polymorphism.
Now when you come to fill up (that is push_back)
BillItems
do it with pointers to whatever particular sandwich or side or drink that is being ordered. That is: any of the derived classes, but not
Product
,
Sandwich
or
Side
or
Drink
themselves; that doesn't make sense - they are just a type place-holder. We need to make it so one can't instantiate object of these types. More about that in a second :+)
It is very important to note that:
there is no conversion to the base pointer; it's just that a derived pointer is an acceptable type in the place of a base pointer. This is very handy: we can have an interface of a few functions rather than dozens to account for all the derived classes, and more derived classes can be added without changing the interface in the base class.
The Product class should have a virtual function:
virtual double Price() const {}
No definition.
All the classes
importantly should have a virtual destructor.
Now each of those
most derived classes should have a
virtual
function called :
virtual double Price() const override;
It's important the the function name be the same for all the classes.
We can disable the instantiation of
Product
,
Sandwich
or
Side
by making their constructors
private
.
Now you can have a range based for loop that goes through all the items in
BillItems
and calls the Price function for each one:
1 2 3
|
for (const auto& Item : BillItems) { // C++14
TotalPrice += Item->Price();
}
|
In C++11:
1 2 3
|
for (const Product* Item : BillItems) { // C++11
TotalPrice += Item->Price();
}
|
Because of the polymorphism, the correct function is called each time.
You could do the same thing as
Price()
with a
Name()
function, and print the receipt by calling both these functions for all the Items in
BillItems
Another thing is to put a virtual function into the
Sandwich
and
Side
class that just prints what it's category is:
"Sandwich"
or
"Side"
, and make use of this when printing the receipt. Again this works because of the polymorphism: If there is no function in the derived class with the correct name, the compiler is able to navigate it's way up the inheritance tree until it does find one. This is handy because we can have 1 function that is the same for lots of derived classes, but we only define it once.
You could extend the whole thing to have Drinks on the menu as well.
With your Menu, I would avoid using strings like that. Provide numerical or char options and use a switch inside a while loop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
bool Quit = false;
while (!Quit) {
// call Menu function returns an unsigned int or char
switch (MenuOption) {
case 1: // use char in single quotes if that is what MenuOption is
// call a function that pushes pointer to derived class into BillItems
break;
// more cases
case 9: // user wants to quit
Quit = true;
break;
default: //catch bad input
// print error message
} // end switch
} //end while
|
There you go !! Heaps of stuff to help you out :+D Hope it all makes sense :+) If you have any questions, I may not be around - I have stuff to do today. But there are plenty of people vastly more experienced than a Back Yard dabbler like me, so don't be afraid to ask ! Regards