Aggregation. Trying to establish connection between objects of two different classes

Hello!
I've created one vector for the drivers class and one for the buses class. The atributes of all the elements are read from the files.
Now I'm trying to establish connection association between the buses and the drivers so that each bus can belong to more than one driver. I'm giving you the code below.
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  #include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
class Worker {
	protected:
		string fullname;
		unsigned int age;
		float experience;
	public:
	    void set_fullname(string name){
			fullname=name;
		}
		string get_fullname(){
			return fullname;
		}
		void set_age(unsigned int years){
			age=years;
		}
		unsigned int get_age(){
			return age;
		}
		void set_experience(float expr){
			experience=expr;
		}
		float get_experience(){
			return experience;
		}
		virtual void showworkerinfo()=0;	
};
class Driver: public Worker{
	private:
		string licencenumber, category;
	public:
		void set_licencenumber(string licence){
			licencenumber=licence;
		}
		string get_licencenumber(){
			return licencenumber;
		}
		void set_category(string cat){
			category=cat;
		}
		string get_category(){
			return category;
		}
		void showworkerinfo(){
			cout<<"|"<<'\t'<<fullname<<'\t'<<"|"<<'\t'<<age<<'\t'<<"|"<<'\t'<<experience<<'\t'<<"|"<<'\t'<<licencenumber<<'\t'<<"|"<<'\t'<<category<<'\t'<<"|"<<endl;
		}
};
class Vehicle {
    protected:
		string brand;
		string color;
		string number;
		unsigned int year_of_production;
		float petrol;
		Driver* driver_;
	public:
		void set_brand(string brandname){
			brand=brandname;
		}
		string get_brand(){
			return brand;
		}
		void set_color(string colour){
			color=colour;
		}
		string get_color(){
			return color;
		}
		void set_number(string nmb){
			number=nmb;
		}
		string get_number(){
			return number;
		}
		void set_year_of_production(unsigned int year){
			year_of_production=year;
		}
		unsigned int get_year_of_production(){
			return year_of_production;
		}
		void set_petrol(float ptrl){
			petrol=ptrl;
		}
		float get_petrol(){
			return petrol;
		}
		void set_driver(unsigned quantity, Driver* driver, ...){
			    Driver *drive;
			    for(drive=driver; quantity>0; quantity--, drive++){
			    	driver_=drive;
			    	driver_->get_fullname();
				}
		}
		void get_driver(){
			cout<<driver_->get_fullname()<<"|"<<driver_->get_licencenumber();
		}
		virtual void showcarinfo()=0;
};
class PublicTransport: public Vehicle{
	protected:
	    unsigned int passengerseats;	
	public:
	    void set_passengersseats(unsigned int seats){
			passengerseats=seats;
		}
		unsigned int get_passengerseats(){
			return passengerseats;
		}	
};
class Bus: public PublicTransport{
	private:
		string route;
	public:
		void set_route(string rout){
			route=rout;
		}
		string get_route(){
			return route;
		}
		void showcarinfo(){
			cout<<"|"<<'\t'<<number<<'\t'<<"|"<<'\t'<<color<<'\t'<<"|"<<'\t'<<brand<<'\t'<<"|"<<'\t'<<year_of_production<<'\t'<<"|"<<'\t'<<petrol<<'\t'<<"|"<<'\t'<< passengerseats<<'\t'<<"|"<<'\t'<<route<<'\t'<<"|"<<endl;
		}
};
void cin_string(string& str,ifstream& file,int size=256,char delim='|'){
	str="";
	getline(file,str,delim);
}
void cin_float(double& f,ifstream& file,char delim='|',int size=256){
    char* cstr= new char[size];
    file.getline(cstr,size,delim); 
    f=atof(cstr); 
    delete[] cstr; 
} 
void cin_int(int& f,ifstream& file,char delim='|',int size=256){
    char* cstr= new char[size]; 
    file.getline(cstr,size,delim); 
    f=atoi(cstr); 
    delete[] cstr;	
}
int main()
{
vector<Bus> buses;
vector<Driver> drivers;
ifstream fbus("buses.txt");
  if(!fbus.is_open ()){ 
  cout<<'\n'<<"Couldn't find buses.txt."<<endl; 
  }
  while(!fbus.eof()){
  	cin_string(carnumber,fbus);
  	cin_string(carcolor,fbus);
    cin_string(carbrand,fbus);
    cin_int(caryear,fbus);
    cin_float(carpetrol,fbus);
    cin_int(carseat,fbus);
    cin_string(carroute,fbus);
    Bus bus;
    bus.set_number(carnumber);
	bus.set_color(carcolor);
	bus.set_brand(carbrand);
	bus.set_year_of_production(caryear);
	bus.set_petrol(carpetrol);
	bus.set_passengersseats(carseat);
	bus.set_route(carroute);
	buses.push_back(bus);
  } 
  fbus.close();
ifstream fdriver("drivers.txt");
  if(!fdriver.is_open ()){ 
  cout<<'\n'<<"Couldn't find drivers.txt."<<endl; 
  }
  while(!fdriver.eof()){
  	cin_string(personname,fdriver);
  	cin_int(personage,fdriver);
    cin_float(personexp,fdriver);
    cin_string(personlicence,fdriver);
    cin_string(personcategory,fdriver);
    Driver driver;
    driver.set_fullname(personname);
    driver.set_age(personage);
    driver.set_experience(personexp);
    driver.set_licencenumber(personlicence);
    driver.set_category(personcategory);
    drivers.push_back(driver);
  }   
  fdriver.close();
buses[0].set_driver(2,&drivers[0],&drivers[1]);
}	

Thank you for your attention and looking forward to any help!
make the driver* a vector and you can have N drivers per, would that work?
One way is to have a two column table in the form of an array, <array>, <vector>, <map> or <multimap> that tabulates driver_id against bus_number. Not unlike a relational database table.

That's the general case which enables easy access to find a driver or a bus.

If a bus has many drivers and you only search on the bus to find out who the driver is then the driver* vector as an attribute of a bus works.
@cruelty free

There are a bunch of things that can be improved in your code.

Avoid using namepsace std; there is lots written about why this is so - Google it. Your IDE may have snippets: On mine I setup some custom keyboard snippets and type s <enter> and std:: is written into the editor. I have my own mnemonics: cssr <enter> writes const std::string&

Having protected variables is generally as bad as having public variables - make them private.

Consider using constructors with a member initialisation list rather than a bunch of set functions.

If one has a public get and set function for every class member, the whole class may as well be a public struct. Instead consider what modifications happen to the object once constructed. There maybe none. If there are things that will happen to the object, design an interface that does those things, rather than focusing on changing individual members. Remember, a class function has access to all the member variables.

Do not loop on eof . Google that.

Did you know that std::cin can read values from a file directly? No need for the long way around like you are doing.

Avoid new and delete unless you have a valid reason, like you a creating a new data structure. Google why new fails when an exception is thrown.

Avid arrays of things when you could use an STL container like std::vector or a class like std::string

Prefer to use emplace_back which calls a constructor directly, rather than creating a copy like push_back does.

Edit:

If a member function does not change any values in an object it should be marked const

With the functions, see which parameters can be marked const

If one has virtual functions, there should be a virtual destructors too. They maybe be defaulted.

When defining a virtual function use the keyword override in the derived class.
Last edited on
As a first refactor, 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
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

class Worker {
protected:
	std::string fullname;
	unsigned age {};
	float experience {};

public:
	void set_fullname(const std::string& name) { fullname = name; }
	std::string get_fullname() const { return fullname; }
	void set_age(unsigned years) { age = years;}
	unsigned get_age() const { 	return age; }
	void set_experience(float expr) { experience = expr; }
	float get_experience() const { return experience; }

	virtual void showworkerinfo() const = 0;
	virtual ~Worker() {}
};

class Driver : public Worker {
private:
	std::string licencenumber, category;

public:
	void set_licencenumber(const std::string& licence) { licencenumber = licence; }
	std::string get_licencenumber() const { return licencenumber; }
	void set_category(const std::string& cat) { category = cat; }
	std::string get_category() const { return category; }

	void showworkerinfo() const override {
		std::cout << "|" << '\t' << fullname << '\t' << "|" << '\t' << age << '\t' << "|" << '\t' << experience << '\t' << "|" << '\t' << licencenumber << '\t' << "|" << '\t' << category << '\t' << "|\n";
	}
};

class Vehicle {
protected:
	std::string brand;
	std::string color;
	std::string number;
	unsigned year_of_production {};
	float petrol {};
	std::vector<Driver*> driver_;

public:
	void set_brand(const std::string& brandname) { brand = brandname; }
	std::string get_brand() const { return brand; }
	void set_color(const std::string& colour_) { color = colour_; }
	std::string get_color() const { return color; }
	void set_number(std::string nmb) { number = nmb; }
	std::string get_number() const { return number; }
	void set_year_of_production(unsigned year) { year_of_production = year; }
	unsigned int get_year_of_production() const { return year_of_production; }
	void set_petrol(float ptrl) { petrol = ptrl; }
	float get_petrol() const { return petrol; }

	template<typename T, typename... Args>
	void set_driver(T driver, Args... args) {
		driver_.push_back(driver);
		set_driver(args...);
	}

	void set_driver() {}

	void show_driver() const {
		for (const auto& d : driver_)
			std::cout << d->get_fullname() << "|" << d->get_licencenumber() << '\n';
	}

	virtual void showinfo() const = 0;
	virtual ~Vehicle() {}
};

class PublicTransport : public Vehicle {
protected:
	unsigned passengerseats {};

public:
	void set_passengersseats(unsigned seats) { passengerseats = seats; }
	unsigned int get_passengerseats() const { return passengerseats; }
};

class Bus : public PublicTransport {
private:
	std::string route;

public:
	void set_route(const std::string& rout) { route = rout; }
	std::string get_route() const { return route; }

	void showinfo() const override {
		std::cout << "|" << '\t' << number << '\t' << "|" << '\t' << color << '\t' << "|" << '\t' << brand << '\t' << "|" << '\t' << year_of_production << '\t' << "|" << '\t' << petrol << '\t' << "|" << '\t' << passengerseats << '\t' << "|" << '\t' << route << '\t' << "|\n";
	}
};

void cin_string(std::string& str, std::ifstream& file, int size = 256, char delim = '|') {
	str.clear();
	std::getline(file, str, delim);
}

void cin_float(float& f, std::ifstream& file, char delim = '|', int size = 256) {
	std::string cstr;

	std::getline(file, cstr, delim);
	f = stof(cstr);
}

void cin_int(int& f, std::ifstream& file, char delim = '|', int size = 256) {
	std::string cstr;

	std::getline(file, cstr, delim);
	f = stoi(cstr);
}

int main()
{
	std::vector<Bus> buses;
	std::vector<Driver> drivers;
	std::ifstream fbus("buses.txt");

	if (!fbus)
		return (std::cout << "\nCouldn't find buses.txt.\n"), 1;

	while (fbus) {
		std::string carnumber, carcolor, carbrand, carroute;
		int caryear {}, carseat {};
		float carpetrol {};

		cin_string(carnumber, fbus);
		cin_string(carcolor, fbus);
		cin_string(carbrand, fbus);
		cin_int(caryear, fbus);
		cin_float(carpetrol, fbus);
		cin_int(carseat, fbus);
		cin_string(carroute, fbus);

		if (fbus) {
			Bus bus;

			bus.set_number(carnumber);
			bus.set_color(carcolor);
			bus.set_brand(carbrand);
			bus.set_year_of_production(caryear);
			bus.set_petrol(carpetrol);
			bus.set_passengersseats(carseat);
			bus.set_route(carroute);

			buses.emplace_back(bus);
		}
	}

	fbus.close();

	std::ifstream fdriver("drivers.txt");

	if (!fdriver)
		return (std::cout << '\n' << "\nCouldn't find drivers.txt.\n"), 2;

	while (fdriver) {
		std::string personname, personlicence, personcategory;
		int personage {};
		float personexp {};

		cin_string(personname, fdriver);
		cin_int(personage, fdriver);
		cin_float(personexp, fdriver);
		cin_string(personlicence, fdriver);
		cin_string(personcategory, fdriver);

		if (fdriver) {
			Driver driver;

			driver.set_fullname(personname);
			driver.set_age(personage);
			driver.set_experience(personexp);
			driver.set_licencenumber(personlicence);
			driver.set_category(personcategory);

			drivers.emplace_back(driver);
		}
	}

	fdriver.close();

	buses[0].set_driver(&drivers[0], &drivers[1]);
}

Last edited on
It would also be helpful if you could post a sample of the input files as file input could probably be simplified using stream extraction rather than getline() and conversion.
Try not to write code that doesn't serve any essential purpose. Use this idea to trim fat:

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

struct driver {
  std::string name, license_number, license_category;
  int age;
  float experience;
};

std::ostream &operator<<(std::ostream &os, driver const &d) {
  return os << "|\t" << d.name << "\t|\t" << d.age << "\t|\t" << d.experience
            << "\t|\t" << d.license_number << "\t|\t" << d.license_category
            << '\n';
}

std::istream &operator>>(std::istream &is, driver &d) {
  // TODO(mbozzi): Put the logic to read a single driver from `is` in here
  // Then remove the following line
  is.setstate(std::ios::failbit);
  return is;
}

struct bus {
  std::string brand, color, number, route;
  int year_of_production, passenger_seats;
  float fuel_in_tank;

  std::vector<std::reference_wrapper<driver>> current_drivers;
};

std::ostream &operator<<(std::ostream &os, bus const &b) {
  return os << "|\t" << b.number << "\t|\t" << b.color << "\t|\t" << b.brand
            << "\t|\t" << b.year_of_production << "\t|\t" << b.fuel_in_tank
            << "\t|\t" << b.passenger_seats << "\t|\t" << b.route << '\n';
}

std::istream &operator>>(std::istream &is, bus &b) {
  // TODO(mbozzi): Put the logic to read a single bus from `is` in here
  // Then remove the following line
  is.setstate(std::ios::failbit);
  return is;
}

int main() {
  std::vector<bus> buses;
  std::vector<driver> drivers;

  // TODO(mbozzi): error checking
  if (std::ifstream fbus{"buses.txt"})
    buses.assign(std::istream_iterator<bus>{fbus}, {});
  if (std::ifstream fdriver{"drivers.txt"})
    drivers.assign(std::istream_iterator<driver>{fdriver}, {});

  // For example, assign all drivers to each bus
  for (bus &b : buses)
    b.current_drivers.assign(drivers.begin(), drivers.end());
}
Topic archived. No new replies allowed.