Display and Save Linked List

I have numerous functions written to implement on a linked list of objects. All I have left to write is the display() and the save_to_file() functions, which are proving to be quite difficult for me. I currently have the code for how it is done with strings instead of Passenger objects, but none of my conversions work. I'll post my whole code below just so everything is provided, but any tips on those two functions would be incredibly helpful. Thanks!

(database.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
#include<list>
#include<algorithm>
#include<iostream>
#include<string>
#include<fstream>
#ifndef passenger_h
#define passenger_h
 using std::string;
 using std::cin;
 using std::cout;
 using std::list;
 using std::endl;

class Passenger {
public:
    Passenger() {}
	Passenger(string, string, string);
	bool operator==(const Passenger&) const;
	bool operator<(const Passenger&) const;
private:
	string fname, lname, destination;
	
};

class Flightlist {
public:
	int menu();
	void read_from_file(string);
	void insert(Passenger p);
	void remove(Passenger p);
	bool check_reservation(Passenger p);
	void display_list();
	void save_to_file(string);
private:
	list<Passenger> flist;
};

#endif 



(database.cc)
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
Passenger::Passenger(string first, string last, string dest)
{
 	fname = first;
 	lname = last;
 	destination = dest;
}

bool Passenger::operator==(const Passenger& p) const
{
	return fname == p.fname && lname == p.lname;
}

bool Passenger::operator<(const Passenger& p) const
{
	return fname < p.fname || (fname == p.fname && lname < p.lname);
}

int Flightlist::menu()
{
	int option;
	cout << endl;
	cout << "Enter one of the following options:" << endl;
	cout << "1. load reservations from file:" << endl;
	cout << "2. reserve a ticket" << endl;
	cout << "3. cancel a reservation" << endl;
	cout << "4. check reservation" << endl;
	cout << "5. display passenger list" << endl; 
	cout << "6. save passenger list" << endl;
	cout << "7. exit" << endl << endl;
	cin >> option;
	cin.get();
	return option;
}

void Flightlist::read_from_file(string filename)
{
	string fname, lname, destination;
	std::ifstream input(filename.c_str());
	while (input >> fname >> lname >> destination) 
	{					
		flist.push_back(Passenger(fname, lname, destination));
	}
	input.close();
}

void Flightlist::insert(Passenger p)
{
	flist.push_back(p);
}

void Flightlist::remove(Passenger p)
{
	flist.remove(p);
}

bool Flightlist::check_reservation(Passenger p)
{
	list<Passenger>::iterator i1, i2;
	i1 = flist.begin();
	i2 = flist.end();
	return flist.end() != find(flist.begin(), flist.end(), p);
}

void Flightlist::display_list()
{
	flist.sort();
	list<Passenger>::iterator i1, i2;
	i1 = flist.begin();
	i2 = flist.end();
	for ( ; i1 != i2; ++i1) {
		cout << *i1 << endl;
	}
}

void Flightlist::save_to_file(string filename)
{
	flist.sort();
	list<Passenger>::iterator i1, i2;
	i1 = flist.begin();
	i2 = flist.end();
	std::ofstream output(filename.c_str());
	for ( ; i1 != i2; ++i1) {
		output << *i1 << " ";
	}
	output.close();
}



(main.cc)
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
int main()
{	
	Flightlist flight_list;
	string fname, lname, destination;

	while (true) 
	{
		switch (flight_list.menu())
		{
			case 1:	
				{
					flight_list.read_from_file("ticket_reservations.dat");
					break;
				}

			case 2: 
				{
					cout << "first name of passenger:" << endl; 
					cin >> fname;
					cout << "last name of passenger" << endl;
					cin >> lname;
					cout << "destination of passenger" << endl;
					cin >> destination;
					flight_list.insert(Passenger(fname, lname, destination));
					break;
				}

			case 3: 
				{
					cout << "first name of passenger:" << endl; 
					cin >> fname;
					cout << "last name of passenger" << endl;
					cin >> lname;
					cout << "destination of passenger" << endl;
					cin >> destination;
					flight_list.remove(Passenger(fname, lname, destination));
					break;
				}

			case 4: 
				{
					cout << "first name of passenger:" << endl; 
					cin >> fname;
					cout << "last name of passenger" << endl;
					cin >> lname;
					cout << "destination of passenger" << endl;
					cin >> destination;
					if (flight_list.check_reservation(Passenger(fname, lname, destination)))
						cout << "this passenger has a ticket reservation" << endl;
					else
						cout << "this passenger does not have a ticket reservation" << endl;
					break;
				}

			case 5:	
				{
					display_list();
					break;
				}

			case 6: 
				{
					save_to_file("ticket_reservations.dat");
				}
				break;
			

			case 7:
				return 0;
		}
	}
	
	return 0;
}
There are a few possible options here.
1. The crudest is to write separate functions to get the values of each of the member variable of class Passenger. (this is to avoid breaking the encapsulation, and keeps the private data from being modified in an uncontrolled manner).

The line
output << *i1 << " ";
might look something like this,
output << i1->getFname() << " " << i1->getLname() << " " << i1->getDestination() << " ";

2. A second choice (and a better one in my opinion) is to write a member function called something like print() or display() for the passenger class.

Then that line could look like this:
i1->print(output);

3. A third alternative is to define an override the operator << for the Passenger class. This would be a friend function to allow it read access to the member variables. Then the line
cout << *i1 << endl;
would look like this:
cout << *i1 << endl;
that is, no change needed, because the Passenger class knows how to print itself to an output stream. It's worth knowing how to do this, even if you decide not to use it here.
Last edited on
@Chervil I'm interested in implementing the second option, but I'm not 100% sure what you mean by it or how to fit it into my code :/
Well, there are two cases that need to be considered. In database.cc at line 71,
cout << *i1 << endl; and at line 83
output << *i1 << " ";
The main difference is one is sending the details to cout, the other to the file output. (There is also the fact that one has endl and the other " ", which is relatively simple to deal with).

One of my suggestions was to replace those two lines with
i1->print(cout); and
i1->print(output);

To do that, add to the class Passenger the public function declaration
 
    void print(std::ostream & os); 

and then add the function definition, something like this:
1
2
3
4
void Passenger::print(std::ostream & os)
{
    os << fname << ' ' << lname << ' ' << destination << '\n';
}


If you like you could remove the << '\n' from function print() and use a separate cout/output statement to output whatever is required afterwards.

I think that's all.

Though I do have suggestion number four, which would be to add to the Passenger class a member function std::string toString() which would return a string containing the three data items suitably spaced in a single string.

Then instead of
cout << *i1 << endl;
you might have
cout << i1->toString() << endl;

Option 3 by the way would look like this:
Add a function declaration in the public section of the Passenger class:
 
    friend std::ostream & operator << (std::ostream & os, const Passenger & p);

and then in database.cc add the function definition. Note, this is not a member function, so it does not need the prefix Passenger::. Also, const is used because the function is not allowed to modify the Passenger object.

1
2
3
4
5
std::ostream & operator << (std::ostream & os, const Passenger & p)
{
    os << p.fname << ' ' << p.lname << ' ' << p.destination;
    return os;
}

Now you can just use cout << *i1 << '\n'; as your existing code does.

You might want to try more than one of these approaches, after all, the format of the data in the file may not necessarily be the same as the format for display on the screen.
Last edited on
Topic archived. No new replies allowed.