Object oriented programming menu troubles

Hello all, i am in a programming 2 class and thought i was understanding quite well, but i am getting stuck with this project my professor assigned. I believe i have all the outline work done but am just in a rut. Any help or guidance would be greatly appreciated!

Create a menu system that allows users to select an item from the below categories:
a. Drink
b. Appetizer
c. Entree
d. Dessert
2. You will use 4 separate input files (one for each category above) where you read in an unknown number of items from each file
a. Each input file will have the item name (string) and the item price (double)
b. Use a generic function to check to see if the file was found
c. User a generic function to get the data from each of the input files
3. Display the subtotal on each menu screen so the customer knows exactly how much is already owed
4. As the customer selects items for purchase, you will need to record the item name, price and the quantity desired inside of variables (vector or array) for output later
5. The customer should be able to remain in a category menu until they are ready to return to the main menu
6. When the customer is finished ordering, display the subtotal, tax, and total on the screen
7. Ask for a tip (make a suggested tip amount with 18%, 20%, 25%), then update the total with the tip amount entered
8. Get payment from the user and display change due to the customer
9. If the customer does not pay enough money, then the program should continue to ask for money until the total is paid in full


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

using namespace std;

class menu {

public:
	
	menu()
	{
		fileCheck(appIn, "app.txt");
		fileCheck(desIn, "des.txt");
		fileCheck(drinkIn, "drink.txt");
		fileCheck(entIn, "ent.txt");

		getData(appIn, appName, appPrice);
		getData(desIn, desName, desPrice);
		getData(entIn, entName, entPrice);
		getData(drinkIn, drinkName, drinkPrice);
	}


	void getData(ifstream& iFile, vector<string>& name, vector<double>& price)
	{

		string tempS;
		double tempD;

		while (!iFile.eof())
		{
			getline(iFile, tempS);
			name.push_back(tempS);

			iFile >> tempD;
			price.push_back(tempD);

			iFile.ignore();

		}

	}

	void menuPrint()
	{
		int choice = 0;
		double subtotal = 0;
		double tax = 0;
		double tip = 0;
		int quantity = 0;


		system("cls");
		cout << "1. Appetizer Menu " << endl;
		cout << "2. Drink Menu " << endl;
		cout << "3. Entree Menu " << endl;
		cout << "4. Dessert Menu " << endl;
		cout << "Subtotal: $" << subtotal << endl;
		cout << "Enter Selection: ";
		cin >> choice;

		if (choice == 1)
		{
			
		}

	}


	void fileCheck(ifstream& iFile, string text)
	{
		iFile.open(text);
		if (!iFile.is_open())
		{
			cout << text << "file not found" << endl;
			exit(1);
		}

	}

	vector<string> appName, drinkName, entName, desName, soldName;
	vector<double> appPrice, drinkPrice, entPrice, desPrice, soldPrice, subtotal, tax, tip;
	vector<int> choice, soldQ;


	ifstream appIn, desIn, entIn, drinkIn;


private:

};


int main()
{


	menu tb;



	return 0;
}
Last edited on
You have a good start.

Line 101, you construct a menu object but you never call any of it's methods.

Line 33: Do not loop on (! stream.eof()) or (stream.good()). This does not work the way you expect. The eof bit is set true only after you make a read attempt on the file. This means after you read the last record of the file, eof is still false. Your attempt to read past the last record sets eof, but you're not checking it there. You proceed as if you had read a good record. This will result in reading an extra (bad) record. The correct way to deal with this is to put the >> (or getline) operation as the condition in the while statement.
1
2
3
  while (stream >> var) // or while (getline(stream,var))
  {  //  Good operation
  }


Line 65: A switch statement is a better choice here.
Last edited on
I am a big fan of NOT using exit.
instead, its a little more work, but cleaner to
1) return a boolean from the offending function, true on success, false on a failure, or an integer (for a code of what went wrong). Or throw, and use exception handling.
2) using the simple bool idea, if you get the wrong answer, unwind naturally back to main via returns, where in main, you also return.
3) At some level, you print why it failed to the user or a log file.

why not exit? exit and terminate are generally reserved for catastrophic failures where if you do not stop RIGHT NOW things can get hurt (eg running a motor too much and breaking something, or your database could get corrupted, or the like) -- use them when there is no other choice. Otherwise, cut a path back through main and exit normally ... in time, hopefully you will see why that is better (its really not clear until you do much larger programs, and hard to explain with a few words).
This should get you over the hump (not tested):
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
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <fstream>
#include <sstream>
using namespace std;

struct Item
{
	string name{};
	double price{};
	int qty{};
};

class menu 
{
	vector<Item> apps, drinks, entrees, deserts, sold;
	double total = 0.0;
	ifstream appIn, desIn, entIn, drinkIn;

public:
	menu()		//	Constructor
	{	//	Open the files
		fileCheck(appIn, "app.txt");
		fileCheck(desIn, "des.txt");
		fileCheck(drinkIn, "drink.txt");
		fileCheck(entIn, "ent.txt");
		//	Read the data
		getData(appIn, apps);
		getData(drinkIn, drinks);
		getData(entIn, entrees);
		getData(desIn, deserts);				
	}

	void getData(ifstream& iFile, vector<Item> & items)
	{
		string line;
		Item temp;

		while (getline(iFile, line))
		{
			stringstream	ss(line);
			ss >> temp.name;
			ss >> temp.price;
			items.push_back(temp);			
		}
	}

	void DisplaySubmenu(vector<Item> & items) 
	{
		size_t subchoice;
		
		cout << "0. Exit this submenu." << endl;
		for (size_t i=0; i<items.size(); i++)
			cout << i+1 << ".  " << items[i].name << "  " << items[i].price << endl;
		while (true)
		{
			Item	temp;
			cout << "Choice: ";
			cin >> subchoice;
			if (subchoice == 0)
			{
				cout << "Total so far: " << total << endl;
				return;
			}
			if (subchoice > items.size())
			{
				cout << "Invalid choice" << endl;
				continue;
			}			
			cout << "How many? ";
			cin >> temp.qty;
			temp.name = items[subchoice].name;
			temp.price = items[subchoice].price * temp.qty;
			sold.push_back(temp) ;
		}		
	}

	void menuPrint()
	{
		int choice = 0;

		system("cls");
		cout << "0. to finish order." << endl;
		cout << "1. Appetizer Menu " << endl;
		cout << "2. Drink Menu " << endl;
		cout << "3. Entree Menu " << endl;
		cout << "4. Dessert Menu " << endl;
		while (1)
		{
			cout << "Enter Selection: ";
			cin >> choice;
			switch (choice)
			{
			case 0: return;

			case 1:	DisplaySubmenu(apps);
					break;

			case 2:	DisplaySubmenu(drinks);
					break;

			case 3:	DisplaySubmenu(entrees);
					break;

			case 4:	DisplaySubmenu(deserts);
					break;
			
			default: cout << "Invalid choice" << endl; 
					break;
			}
		}
	}

	void FinalCheck()
	{
		cout << "Final Check" << endl;
		for (auto item : sold)
			cout << item.name << "  " << item.price << endl;
		cout << "Total: " << total << endl;		
	}

	void fileCheck(ifstream& iFile, string text)
	{
		iFile.open(text);
		if (!iFile.is_open())
		{
			cout << text << "file not found" << endl;
			exit(1);
		}

	}	
};

int main()
{
	menu tb;

	tb.menuPrint();
	tb.FinalCheck();
        //  tb.CalculateTax();
        //  tb.GetTip();
        //  tb.Get_Payment();
	return 0;
}

Last edited on
Rather than have 4 of everything, this can be generalised by having a container of available files - so adding a new category is simply a matter of adding a new entry to the container. As a first 'proof of concept' consider:

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
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <algorithm>

struct Cats {
	std::string desc;
	std::string fname;
};

struct Item {
	std::string name;
	double price {};
};

struct Order {
	Item* item {};
	unsigned qty {};
};

using Items = std::vector<Item>;
using Avail = std::vector<Items>;

bool fileRead(const std::string& fnam, Items& itms) {
	if (std::ifstream ifs { fnam }) {
		itms.clear();

		for (Item itm; ifs >> itm.name >> itm.price; itms.push_back(itm));
		return true;
	}

	return false;
}

int main() {
	const std::vector<Cats> cats { {"Drink", "drinks.txt"}, {"Appetizer", "appetizers.txt"}, {"Entree", "entree.txt"}, {"Dessert", "desserts.txt"} };
	Avail items(cats.size());
	std::vector<Order> order;
	double total {};

	std::cout << std::setprecision(2) << std::fixed;

	for (size_t c {}; c < cats.size(); ++c)
		if (!fileRead(cats[c].fname, items[c]))
			std::cout << "Category " << cats[c].desc << " is not available\n";

	for (bool quit {}; !quit; ) {
		int opt {};

		std::cout << "\nMain menu\n";
		for (size_t c {}; c < cats.size(); ++c)
			if (items[c].size())
				std::cout << c + 1 << ".  " << cats[c].desc << '\n';

		std::cout << "0.  Place order\n";
		std::cout << "Enter option: ";
		std::cin >> opt;

		if (opt < 0 || opt > cats.size() || items[opt - 1].empty())
			std::cout << "Invalid option\n";
		else
			for (bool qt {}; !(quit = (opt == 0)) && !qt; ) {
				int o {};

				std::cout << '\n' << cats[opt - 1].desc << " menu\n";
				for (size_t c {}; c < items[opt - 1].size(); ++c)
					std::cout << c + 1 << ".  " << items[opt - 1][c].name << "  " << items[opt - 1][c].price << '\n';

				std::cout << "0.  Return to main menu\n";
				std::cout << "Enter option: ";
				std::cin >> o;

				if (o < 0 || o > items[opt - 1].size())
					std::cout << "Invalid option\n";
				else if (!(qt = o == 0)) {
					unsigned qty {};

					std::cout << "You have chosen " << items[opt - 1][o - 1].name << '\n';
					std::cout << "Enter quantity: ";
					std::cin >> qty;

					if (const auto ret { std::find_if(order.begin(), order.end(), [&](const auto& e) {return e.item == &items[opt - 1][o - 1]; }) }; ret != order.end())
						ret->qty += qty;
					else
						order.emplace_back(&items[opt - 1][o - 1], qty);

					total += items[opt - 1][o - 1].price * qty;
					std::cout << "\nOrder total is " << total << '\n';
				}
			}
	}

	std::cout << "\nYour order is:\n";
	std::cout << std::setw(20) << std::left << "Name" << std::setw(10) << std::right << "Price" << std::setw(10) << "Qty" << std::setw(10) << "Cost" << '\n';

	for (const auto& o : order)
		std::cout << std::setw(20) << std::left << o.item->name << std::right << std::setw(10) << o.item->price
		 << std::setw(10) << o.qty << std::setw(10) << o.item->price * o.qty << '\n';

	std::cout << "\n\nOrder total is " << total << '\n';
}


Note that spaces are not allowed in the description. If spaces are required then this makes parsing the file contents more involved.



Main menu
1.  Drink
2.  Appetizer
3.  Entree
4.  Dessert
0.  Order
Enter option: 1

Drink menu
1.  Coke  1.99
2.  Pepsi  1.99
3.  Sprite  1.99
4.  Water  1.50
0.  Return to main menu
Enter option: 1
You have chosen Coke
Enter quantity: 3

Order total is 5.97

Drink menu
1.  Coke  1.99
2.  Pepsi  1.99
3.  Sprite  1.99
4.  Water  1.50
0.  Return to main menu
Enter option: 0

Main menu
1.  Drink
2.  Appetizer
3.  Entree
4.  Dessert
0.  Order
Enter option: 2

Appetizer menu
1.  CheeseSticks  3.50
2.  FriedPickles  4.99
3.  Calamari  6.50
0.  Return to main menu
Enter option: 1
You have chosen CheeseSticks
Enter quantity: 1

Order total is 9.47

Appetizer menu
1.  CheeseSticks  3.50
2.  FriedPickles  4.99
3.  Calamari  6.50
0.  Return to main menu
Enter option: 2
You have chosen FriedPickles
Enter quantity: 2

Order total is 19.45

Appetizer menu
1.  CheeseSticks  3.50
2.  FriedPickles  4.99
3.  Calamari  6.50
0.  Return to main menu
Enter option: 0

Main menu
1.  Drink
2.  Appetizer
3.  Entree
4.  Dessert
0.  Order
Enter option: 3

Entree menu
1.  Steak  17.50
2.  SteakAndShrimp  18.50
3.  ChickenFriedRice  13.00
4.  SeafoodFeast  20.00
5.  Pork  16.00
0.  Return to main menu
Enter option: 1
You have chosen Steak
Enter quantity: 1

Order total is 36.95

Entree menu
1.  Steak  17.50
2.  SteakAndShrimp  18.50
3.  ChickenFriedRice  13.00
4.  SeafoodFeast  20.00
5.  Pork  16.00
0.  Return to main menu
Enter option: 2
You have chosen SteakAndShrimp
Enter quantity: 1

Order total is 55.45

Entree menu
1.  Steak  17.50
2.  SteakAndShrimp  18.50
3.  ChickenFriedRice  13.00
4.  SeafoodFeast  20.00
5.  Pork  16.00
0.  Return to main menu
Enter option: 3
You have chosen ChickenFriedRice
Enter quantity: 1

Order total is 68.45

Entree menu
1.  Steak  17.50
2.  SteakAndShrimp  18.50
3.  ChickenFriedRice  13.00
4.  SeafoodFeast  20.00
5.  Pork  16.00
0.  Return to main menu
Enter option: 0

Main menu
1.  Drink
2.  Appetizer
3.  Entree
4.  Dessert
0.  Order
Enter option: 4

Dessert menu
1.  Tiramisu  3.50
2.  LavaCake  4.99
3.  SmoresCake  6.50
0.  Return to main menu
Enter option: 2
You have chosen LavaCake
Enter quantity: 4

Order total is 88.41

Dessert menu
1.  Tiramisu  3.50
2.  LavaCake  4.99
3.  SmoresCake  6.50
0.  Return to main menu
Enter option: 0

Main menu
1.  Drink
2.  Appetizer
3.  Entree
4.  Dessert
0.  Order
Enter option: 0

Your order is:
Name                     Price       Qty      Cost
Coke                      1.99         3      5.97
CheeseSticks              3.50         1      3.50
FriedPickles              4.99         2      9.98
Steak                    17.50         1     17.50
SteakAndShrimp           18.50         1     18.50
ChickenFriedRice         13.00         1     13.00
LavaCake                  4.99         4     19.96


Order total is 88.41

Last edited on
Thank you all! i will reply again later as i work on it and get it running!
If you post a file data sample, we can provide advice as to how best read it.
Topic archived. No new replies allowed.