Accessing derived class within the base class

closed account (Sw07fSEw)
I've been messing around with inheritance this afternoon trying to do some examples to get a feel for it. I came up with a sample scenario of a pizza shop. Customers can place orders. Each order can have pizzas, sandwiches, sides etc. There are different types food within each category. For example, a container of sandwiches might contain instances of a tuna sandwich, a cheesesteak and a meatball sub. Since these classes are derived from sandwich, I've been able to put them into a container.

I'm trying to use inheritance with 3 levels of classes. Order having the most hierarchy followed by sandwich, followed by different types of sandwiches (i.e. a cheesesteak class, meatball sub class) and so forth. When a customer places an order, I'd like to be able to store the components of their order. So if they order a sandwich, I would have a container of sandwiches which might contain a cheesesteak, a meatball sub, etc. If they order a side like french fries, and garlic knots, I could put each instance into a container of sides.

I'm running into trouble because the compiler can't find the base class. I'd like to have containers of different class types in my Order class; a container of pizzas, sandwiches and sides. However, I can't define them first because they're inheriting properties from my base class. Could someone point me in the right direction?

Order.h
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
#pragma once
#include <string>
#include <vector>
#include "Sandwiches.h"

class Order {
private:
	std::string customer_name;
	
protected:
	std::vector<Sandwich> sandwiches; // vector of different sandwhich types
	double total_cost;
public:
	Order(std::string customer_name);
	std::string getCustomerName();
	void updateTotal(double cost);
	double getTotalCost();
	void addSandwich(Sandwich &sandwich);
};

Order::Order(std::string customer_name) {
	this->customer_name = customer_name;
}
void Order::updateTotal(double cost) {
	total_cost += cost;
}
double Order::getTotalCost() {
	return total_cost;
}
std::string Order::getCustomerName() {
	return customer_name;
}
void Order::addSandwich(Sandwich &sandwich) {
	sandwiches.push_back(sandwich);
}


Sandwich.h
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
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>


class Sandwich: protected Order {
private:
	int size;
	double cost;
	std::string type;
public:
	Sandwich();
	Sandwich(std::string type);
	void displayDefaultToppings();
	void addTopping();
	void removeTopping();
	double getSandwichCost();

};
Sandwich::Sandwich(std::string type) {
	this->type = type;
}


Sandwiches.h
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
#pragma once
#include "Sandwich.h"

class Cheesesteak : public Sandwich {
private:
	std::vector<std::pair<std::string, bool>> toppings;
	std::string size;
public:
	Cheesesteak();
	void setToppings();
	std::vector < std::string > getCurrentToppings();

};
Cheesesteak::Cheesesteak() {
	this->size = "Large";
}
void Cheesesteak::setToppings() {
	toppings.push_back(std::make_pair("onion", true));
	toppings.push_back(std::make_pair("marinara sauce", false));
	toppings.push_back(std::make_pair("green peppers", true));
	toppings.push_back(std::make_pair("mushrooms", false));
}
std::vector < std::string > Cheesesteak::getCurrentToppings() {
	std::vector< std::string> activeToppings;
	for (std::vector<std::pair<std::string, bool>>::iterator it = toppings.begin(); it != toppings.end(); ++it) {
		if (it->second == true) {
			activeToppings.push_back(it->first);
		}
	}
	return activeToppings;
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include "Order.h"
#include "Sandwich.h"
#include "Sandwiches.h"

int main() {
	Order EricsOrder("Eric");
	std::string item_to_add;
	
	std::cout << "What would you like to order: \n";
	std::getline(std::cin, item_to_add);

	if (item_to_add == "cheesesteak") {
		Cheesesteak temp;
		EricsOrder.addSandwich(temp);
	}

	return 0;
}
Try defining your containers after you define the base class Order
Otherwise, it should work.
Good luck!
Your class hierarchy doesn't make sense to me. Make sure you're clear on what you're modeling in terms of "is-a" and "has-a" relationships. For example, Order "has-a" collection of Sandwiches (Order.h line 11). That's sensible. But then you say that Sandwich "is-a" Order (Sandwich.h line 8). This doesn't make sense. Do Sandwiches each contain a collection of Sandwiches?

Also, be careful in Cheesesteak. You're making a property in class Cheesesteak called size of type std::string. But Cheesesteak already inherits something called size (an int) from Sandwich.

Draw out your object relationships on paper and see if it helps you model these relationships more properly in code.
I agree that you should review your design.

Also, be careful with object slicing.
std::vector<Sandwich> sandwiches; should be std::vector< some_smart_pointer<Sandwich> > sandwiches; to allow you to store objects of the derived classes.
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
Last edited on
As it stands now, some may argue that all the things are the same: they all have a Name, Price, Quantity, Subtotal. However it's not hard to come up with some specialisation for them: Pizza toppings, Sandwich fillings, Parmesan cheese on the Pasta etc. These would justify having the inheritance tree and the polymorphism - got to keep the Parmesan out of the Coca-Cola !!!

Mind though, I wouldn't have Coca-Cola, Sprite, Mountain Dew etc - they are all SoftDrinks but I might have FruitJuice, Coffee etc if there was a reason to separate them. For example, here in Australia there are different Tax rates for locally produced food / drinks. Edit: that's not a good example Tax is just a value which could vary from item to item.

I spent ages doing my long post: I didn't see the previous 3 replies.
Last edited on
closed account (Sw07fSEw)
Hey guys thanks for the replies. I really only started trying to dive into inheritance today.

@Booradley thanks for pointing out the 'is-a' and 'has-a' concepts. That made it a lot easier to understand what inherits what. Calling a sandwich an order doesn't really make sense, but calling a cheesesteak a sandwich does. On second thought, I'm not sure that sandwich needs to inherit any properties of order.

@ne555 I'm not experienced enough to know what a smart pointer is. Could you explain in simple terms how that's more advantageous than the container in the format I have it in?

A smart pointer is just a wrapper that would manage things like copy and deletion of the pointers (memory ownership).

Now you are doing
1
2
		Cheesesteak temp;
		EricsOrder.addSandwich(temp);
which occurs in object slicing, all the variables added by cheesesteak will be lost.
You need to change it to EricsOrder.addSandwich( new Ceesesteak );, storing pointers instead.

So now you'll be dealing with dynamic memory, and you need to worry about releasing the memory properly, and to make sure that your pointers are valid. The smart pointers will help you with that.


> virtual double Price() const {} No definition.
err... that's a definition. (one with undefined behaviour, by the way)
Perhaps you mean virtual double Price() const = 0; making it pure virtual.

> We can disable the instantiation of Product, Sandwich or Side by making their constructors private.
if they are private, you could not access them from a derived class either, so you can't construct derived objects.
Perhaps you mean to make them protected.

However, an object from an abstract class (one with a pure virtual member function) can't be instantiated, there is no need to do more.
@ne555

I had a misunderstanding about pure virtual functions: I thought they must be over-riden. Which is true, but the further qualification is that: any class that doesn't override the function will be abstract too. ++ThingsLearnt; And that is exactly what we want for the Pizza, Sandwich et al classes :+) The over-riding happens at the leaf classes.

Perhaps you mean to make them protected.
However, an object from an abstract class (one with a pure virtual member function) can't be instantiated, there is no need to do more.


Ah, yes my bad, and that goes back to my incomplete knowledge of the pure virtual function.

While we are at it: It would be good to only declare member variables Name, Price, Quantity etcetera once only, not again for every derived class. I had read somewhere that it is still possible to: set values of member variables in the base class via it's constructor from the derived class constructor ; and access those values through the base class interface from the derived class. All of this despite the base class being abstract, because we do not instantiate the base in some other scope like main say. Just wondering what your view is on that ? I will have a go at some code shortly :+)

Thanks for your advice - it's always great to receive it from an expert :+)
closed account (Sw07fSEw)
So I took your guy's advice and tried to structure the program better. I created another class called Product. Since pizzas, sandwiches, sides are all types of products, I figure I can store all them into a vector of Product pointers.

When a customer places an order, their order contains their own personal vector of products. I thought it would make sense to place this vector as private within my Order class, is this the best place to put it?

I tried using a vector of type, Product pointers so I can store a variety of different menu items called billedItems. I think this is the smart pointer concept ne555 was talking about? However, I'm having trouble understanding the full scope.

I wrote a handful of member functions inside of class Pizza, such as addTopping(), removeTopping(). If a customer adds an item to their order, I want to give them the option of going back and adding/removing toppings, changing the size, etc. The problem is, I can't access the functions.

In line 21 of Order.h, I declare a Pizza object is equal to a new Meatlover pizza. I have a couple lines of code in lines 23-25 to verify the member functions work correctly. However, when I push that pointer to the Pizza back into the vector of billedItems, I lose track of the scope. Since I'm essentially adding a pizza as the 1st element of billedItems, I would think that billedItems[0] would refer to the 1st object, which also happens to be a pizza. But when I try to access the member functions via billedItems[0]-> they're unavailable. Even though I pushed the pizza pointer into the vector, is it still considering billedItems[0] to be of type Product?How can I add instances of pizzas to billedItems and still access the pizza member functions? Follow up question, would it be better to just add the specific item into billedItems all together? i.e. billedItems.push_back(new Meatlover("Large", "Meatlover", "Regular"); Logically this makes more sense, and since Meatlover inherits from Pizza, I would still be able to access the member functions once I can figure out to get them in the right scope.

Here's the code:

Order.h
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
#pragma once
#include <string>
#include <vector>
#include "Product.h"

class Order {
private:
	std::string customer_name;
	std::vector<Product* > billedItems;
public:
	Order(std::string customer_name) { this->customer_name = customer_name; }
	void addProduct();
};

void Order::addProduct() {
	std::string menu_item;

	std::cout << "What would you like to add: ";
	std::getline(std::cin, menu_item);

	Pizza *p_pizza = new Meatlover("Large", "Meatlover", "Regular"); 

	p_pizza->addTopping("Blackolive");
	p_pizza->viewCurrentToppings();
	std::cout << p_pizza->Price() << std::endl;

	billedItems.push_back(p_pizza);
	std::cout << billedItems[0]->Price() << std::endl;
}
[/code}

Product.h
[code]
#pragma once
#include <string>

class Product {
private:
	std::string menu_item;
public:
	Product(std::string menu_item) { this->menu_item = menu_item; }

	std::string getMenuItem() { return menu_item; }

	virtual double Price() const = 0; //declares Product as abstract base class
	// the price of different pizzas will vary
};


Pizza.h
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
#pragma once
#include "Product.h"
#include <vector>
#include <map>
#include <iostream>

class Pizza : public Product {
protected:
	std::string size;
	std::string name;
	std::string crust_type;

	std::map<std::string, bool> toppings;

public:
	Pizza(std::string size, std::string name, std::string crust_type);

	void setSize(std::string size) { this->size = size; }
	void setName(std::string name) { this->name = name; }
	void setCrustType(std::string crust_type) { this->crust_type = crust_type; }

	std::string getSize() { return size; }
	std::string getName() { return name; }
	std::string getCrustType() { return crust_type; }

	void addTopping(std::string key) { toppings[key] = true; }
	void removeTopping(std::string key){ toppings[key] = false; }

	void viewCurrentToppings();

	virtual double Price() const;
};
Pizza::Pizza(std::string size, std::string name, std::string crust_type) : Product(name) {
	this->size = size;
	this->name = name;
	this->crust_type = crust_type;

	toppings["Pepperoni"] = false; // turn off all toppings by default.
	toppings["Sausage"] = false; // different specialty pizzas will inherit this map
	toppings["Ham"] = false; // and have their predefined toppings 'turned on'.
	toppings["Hamburger"] = false;
	toppings["Chicken"] = false;
	toppings["Philly Steak"] = false;
	toppings["Onion"] = false;
	toppings["Blackolive"] = false;
	toppings["Extra Cheese"] = false;
	toppings["Pineapple"] = false;
	toppings["Green Pepper"] = false;
	toppings["Bell Pepper"] = false;

}
void Pizza::viewCurrentToppings() { // display all toppings set to true
	for (std::map<std::string, bool>::iterator it = toppings.begin(); it != toppings.end(); ++it) {
		if (it->second == true) {
			std::cout << it->first << std::endl;
		}
	}
}
double Pizza::Price() const {
	return 8.50;
}


Meatlover.h
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
#include "Pizza.h"

class Meatlover : public Pizza {

public:
	Meatlover(std::string size, std::string name, std::string crust_type) : Pizza(size, name, crust_type) {
		toppings["Pepperoni"] = true;
		toppings["Sausage"] = true;
		toppings["Onion"] = true;
	};
};


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Pizza.h"
#include "Meatlover.h"
#include "Pepperoni.h"
#include "Product.h"
#include "Order.h"

#include <vector>
#include <iostream>


int main() {

	Order EricsOrder("Eric");

	EricsOrder.addProduct();

	return 0;

}

Last edited on
About smart pointers
Pizza *p_pizza = new Meatlover("Large", "Meatlover", "Regular");
there you are allocating memory, when you are done with it you should release it.
By instance, the destructor of Order may be
1
2
3
4
Order::~Order(){
   for(size_t K=0; K<billedItems.size(); ++K)
      delete billedItems[K];
}
You'll also need to handle cases like copying an order Order Tim = Eric_order;
With a smart pointer you avoid having to code all that, you just chose the one that gives you the behaviour that you want.
By instance, std::unique_ptr would make the delete in the destructor, and would say that it is impossible to copy.
with std::shared_ptr the copy means that they point to the same object, so Eric and Tim would share a pizza
with nih::clone_ptr the copy means Tim would have its own pizza, that's identical to Eric's.


> But when I try to access the member functions via billedItems[0]-> they're
> unavailable. Even though I pushed the pizza pointer into the vector, is it
> still considering billedItems[0] to be of type Product?
yes, you have declared std::vector<Product* > billedItems;, so `billedItems' holds pointers to Product.
You may do billedItems[0] = new Cheesesteak instead, you cannot know at compile-time (writing code) what will happen at run-time (executing the program)
So the compiler would only know about the functions in `Product', whatever the object actually is.


> How can I add instances of pizzas to billedItems and still access the pizza
> member functions?
you may try to cast it. http://www.cplusplus.com/doc/tutorial/typecasting/ (see dynamic_cast)
or you may store Pizza* instead of Product*, there is no need to go to the most base class.
or you may provide virtual member functions in Product that would allow you to operate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Product{
public:
   virtual void edit() = 0;
};

class Pizza: public Product{
public:
   virtual void edit() override{
      this->edit_crust();
	  this->edit_size();
	  //or
	  //globalfunction_edit_pizza(*this);
   }
}

or you can say that an update is the same as a delete and an insert,
1
2
this->remove_order(0);
this->add_new_order();

Last edited on
closed account (Sw07fSEw)
Thanks! A couple questions on actually deleting the memory. How would I go about deleting a specific instance of Pizza in a smart pointer of pizzas? I.e. std::vector<Pizza* > pizzas . If a customer were to have 3 pizzas in their order, how could I delete a single pizza instance from pizzas? I wrote the following code, but I'm not convinced it's right. It compiles, but I'm not sure if it actually releases the memory.

Order.h
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
#pragma once
#include <string>
#include <vector>

class Order {
private:
	std::string customer_name;
	std::vector<Pizza* > pizzas;
public:
	Order(std::string customer_name) { this->customer_name = customer_name; }
	void addPizza();
	void removePizza();
};

void Order::addPizza() {
	std::string pizzaType;

	std::cout << "What type of Pizza would like to add: ";
	std::getline(std::cin, pizzaType);

	if (pizzaType == "Meatlover") {
		pizzas.push_back(new Meatlover("Large", pizzaType, "Regular"));
	}
	else if (pizzaType == "Hawaiian") {
		pizzas.push_back(new Hawaiian("Large", pizzaType, "Regular"));
	}
}
void Order::removePizza() {
	std::string pizzaToDelete;

	std::cout << "You currently have " << pizzas.size() << " pizza(s) in your cart.\n";
	std::cout << "Which pizza would you like to remove: ";
	std::getline(std::cin, pizzaToDelete);

	for (size_t i = 0; i < pizzas.size(); i++) {
		if (pizzas[i]->getName() == pizzaToDelete) { //match the names and delete that pizza
			std::cout << "Deleting pizza...\n";
			delete pizzas[i]; // how do I know if this is correct?
		}
	}

	std::cout << "There are now " << pizzas.size() << " pizza(s) in your cart.\n"; // size is the same after deletion
}



If I delete the pointer from the vector, would the vectors size decrease by 1? How can I verify the instance has actually been deleted?
Last edited on
Hi,

I wrote some code too, but I don't want to confuse the situation by posting it here. Hopefully it's not too much info right now - perhaps these ideas could be in the background while you do the things ne555 is suggesting :+)

Although I would like to mention some things - just as food for thought :+)

My code was bare bones, quick and dirty: no complications with toppings or sizes for example. So you are ahead of me there.

There is one thing that makes sense on one hand, but might be a little counter-intuitive on the other hand. So here goes ....

All the Products have the variables Name , Price, Quantity, and LineTotal in common, so I put them all in the Product class. To me, this makes sense: one should try to push things (variables and functions) up the tree as much as possible within reason. That is, not gratuitously, only as far up as it is valid to do so.

On the other hand this might seem counter-intuitive because the base class is abstract, but the derived classes are still able to use it's interface and variables because we don't instantiate it anywhere else. This might also seem unusual because base classes often have a bunch of pure virtual functions and not much else. Not sure whether this approach is a good idea - perhaps someone with way more experience than a mere dabbler like me can comment on that :+)

With the Pizza class, it could have a container of all the normal pizzas names (Meatlovers .... etc) and their individual prices. And another container of all the toppings with their individual prices for custom build pizzas. Then we might be able to avoid having lots of classes under the Pizza class, maybe just one for the actual pizza - to record it's details, actual toppings final price etc. This would be better than having 20 classes under the Pizza class. So this thinking could apply to the other categories of food too: Sandwiches, Sides, Pasta, Desserts, Drinks.

With Menus,we could have a base Menu class: from which the MainMenu , PizzaMenu, SandwichMenu etc could all derive. An instance of those menus could live in the relevant class: PizzaMenu in the Pizza class.

With new and delete: I avoid them like the plague. But I won't say anything else on that: You are in very good hands with ne555

About this code:
52
53
54
55
56
57
58
void Pizza::viewCurrentToppings() { // display all toppings set to true
	for (std::map<std::string, bool>::iterator it = toppings.begin(); it != toppings.end(); ++it) {
		if (it->second == true) {
			std::cout << it->first << std::endl;
		}
	}
}


If one wants to process all the elements in a container, I often use a ranged based for loop:

52
53
54
55
56
57
58
void Pizza::viewCurrentToppings() const { // display all toppings set to true
	for (const auto& Elem : toppings) {
		if (Elem->second == true) {
			std::cout << Elem->first << std::endl;
		}
	}
}


I find that easier than dealing with the iterators - the range based for loop does the same thing.

Something that ne555 taught me quite awhile back: Use member initialization lists rather than assignment in your constructors. Make sure all of the member variables are initialised, and in the same order as in the class definition.

http://en.cppreference.com/w/cpp/language/initializer_list

Here is one of mine, with some formatting as well:

1
2
3
4
5
6
7
8
Product::Product(const std::string &NameArg,
                 const     double PriceArg,
                 const std::size_t QuantityArg )
    : //member initialization list
        Name(NameArg),
        Price(PriceArg),
        Quantity(QuantityArg),
        LineTotal(Quantity * Price) {}


Good Luck !!
As mentioned in my PM reply, I am making a reply here. I don't wish for ne555 et al. to be offering expert advice here, then me providing amateur advice behind his back in a PM

edpgolfer PM wrote:
I
I couldn't find a definitive answer so I'll ask. Do you think I can still use 3 hierarchy's of classes to define my menu items. I like the general Product class you suggested, so that would be my abstract base class. Then I would still like to have some child classes of Product, like Pizza, Side, Sandwich, Drink etc. Pizza objects all have common attributes like crust or size, so having a class specifically for pizza makes sense. Then ultimately I would have specific types as of pizza as a class, for example class Hawaiian_Pizza, or Meatlover. Essentially have specific classes for specialty pizzas.

I would like to have a middle hierarchy class like Pizza, because I think it would be useful to include member functions like addTopping or removeTopping so I can call those functions within my specific types of pizza classes.

For example, if I had class Hawaiian_Pizza: public Pizza , I would like to inherit a public member removeTopping from Pizza so I could call that function on an instance of my Hawaiian_Pizza.

1
2
Hawaiian_Pizza myPizza;
myPizza.removeTopping(blackolives);


So to reiterate what I said earlier:

TheIdeasMan wrote:
With the Pizza class, it could have a container of all the normal pizzas names (Meatlovers .... etc) and their individual prices. And another container of all the toppings with their individual prices for custom build pizzas. Then we might be able to avoid having lots of classes under the Pizza class, maybe just one for the actual pizza - to record it's details, actual toppings final price etc. This would be better than having 20 classes under the Pizza class. So this thinking could apply to the other categories of food too: Sandwiches, Sides, Pasta, Desserts, Drinks.


So by that I meant:

1
2
3
class Product {};
class Pizza : public Product {};
class PizzaActual : public Pizza {};


With similar idea for the others Sandwich, Side etc.

If someone orders several different pizzas: then there would be several instances of PizzaActual objects to reflect that. But several pizzas of the same type would be 1 PizzaActual with a Quantity of 3 say.

I guess this is an example where "MeatLovers" pizza is a value for a Name attribute (that is: member variable) rather than a class.

In my original post, I was trying to cook up a scenario that demonstrated polymorphism, some of the finer details weren't quite right.
Topic archived. No new replies allowed.