sorry i'm new to c++ and i feel a little stupid for asking, but i can't get it to work after hours of googling and i can't find what i'm doing wrong
the task is pretty easy:
i want to have employees that have name, age etc (those work)
and i want these employees to be stored inside an array.
so i have:
class Employee {
public:
Employee(string, string, int, int);
string name;
string firstName;
int birthYear;
int usedVacation;
int getAge();
};
and then the list:
class EmployeeList {
public:
int addEmployee(string, string, int, int);
Employee eList[500];
};
what i want is: an object that holds an array of Employees, with methods to add/edit etc them.
so i define the addEmployee method outside the class as follows:
int EmployeeList::addEmployee(string first, string last, int year, int used) {
int i = 0;
for (i; i < this.eList.length; i++) {
if (this.eList[i].deleted == true) {
this.eList[i] = {
firstName: first,
lastName : last,
birthYear : year,
usedVacation : used,
deleted : false };
} else {
this.eList.push({ firstName: first, lastName : last, birthYear : year, usedVacation : used, deleted : false });
}
return i;
}
};
As you probably instantly see, there's a lot wrong with that.
All of the this throw Expression must have class type in VS2015,
also identifier firstName is undefined and identifier lastName is undefined,
but in my eyes, there's nothing wrong with my code.
i'm pretty sure this is a very basic thing i just didn't get yet, but i just can't find out, where the problem is.
I defined methods outside Employee, and this works there without a problem (although with this->, but i tried that and it doesn't work either)
please forgive my lack of skills, i come from javascript :(
this.eList[i] =
this is a pointer, not a reference, so you access the members via this->eList. But 99.99% of the time, it's completely unnecessary. You're inside a member method, so the compiler knows what this is. All you need is eList[i] =.
this.eList.push({
First a brief tutorial with arrays in C++. Employee eList[500] doesn't make an array that can hold 500 Employees, eList is 500 Employees. Forever and always. They are are instantly constructed with the default constructor (or will be once you give Employee a default constructor. This is required if you want to have objects in an array, except in very advanced cases).
this.eList.length
There are three actions you can do with arrays: you can access an element with the [i] syntax, they magically convert to a pointer to the first item very often, and finally, if and only if they're a member of a struct, they can be copied. That's all you can do with them. There is no push, because as I said, it is 500 Employee. There is no length member. Yours is always 500 Employees.
if (this.eList[i].deleted == true)
You gave each Employee 4 members, deleted was not one of them. Instead of keeping track of which Employee objects are unused, the normal thing is to keep all the employees in the first few slots, and give EmployeeList a count to keep track of how many "live" employees there are. The live ones are in indecies 0-count. The employees at count-500 are "deleted". Unfortunately, this does mean that when one is deleted, you have to shift forward all the ones after that.
this.eList[i] = {
firstName: first,
lastName : last,
Employee does not have a lastName. The right way to construct an Employee is via the constructor you declared: Employee(string, string, int, int). So that line should probably be eList[i] = Employee(first, last, year, used);. This creates a new Employee object, and then copies it into that slot of the array. Alternatively, just assign the members one by one.
How about something like:
#include<string>
class Employee
{
public:
std::string firstname;
std::lastname;
int birthyear;
int usedVacation;
void setFirstname(std::string fname){firstname = fname;}
void setLastname(std::string lname){lastname = lname;}
void setBirthyear(int year){birthyear = year;}
void setVacation(int vac){usedVacation = vac;}
};
class EmployeeList
{
public:
int count;
EmployeeList eList[500];
EmployeeList()
{
count = 0;
}
void addEmployee(std::string fname, std::string lname, int year, int vac);
void removeEmployee(std::string fname, std::string lname, int year, int vac);
};
void EmployeeList::addEmployee(std::string fname, std::string lname, int year, int vac)
{
//some stuff goes here
count++;
}
void EmployeeList::removeEmployee(std::string fname, std::string lname, int year, int vac)
{
//some stuff goes here
count--;
}
BTW I am not sure where your push, deleted, and length methods came from? You will likely also want to add more methods then what I have written, for example a method to return count. You can also add get methods to the employee class and make your member variables private. I hope this is of some help. Goodluck!
Related
I'm a beginner in C++ and I am trying to create a program which simulates a flight management system. I have created classes to simplify the process. Right now, I have a class named "Flight" which has other user-defined data types as its attributes. For example, it includes two "Date" objects, for arrival and departure dates of my flight object. I also have an array of 30 "Passenger" objects which represent the passengers on my flight. I'm experiencing difficulty making changes to this array though. I need to write a member function for my Flight class which can delete Passengers from the array given the ID (which is an attribute of Passenger).
I want to try to implement this function by passing it an integer "removeID". This value is then compared to the ID's of the passengers in the array. If it matches, the entry is "deleted" essentially freeing the space in the array.
My class Flight is defined as such in its own header file.
#include <string>
#include "Date.h"
#include "Time.h"
#include "Passenger.h"
#ifndef FLIGHT_H_
#define FLIGHT_H_
class Flight
{
public:
Flight(std::string, Date, Date, Time, Time);
float flightTime();
void addPassenger(Passenger);
void removePassenger(int);
bool listChecker(Passenger);
void flightListPrinter()const;
int seatsRemaining();
private:
std::string flightNumber;
Date arrivalDate;
Date departureDate;
Time arrivalTime;
Time departureTime;
std::string destination;
Passenger* passengerList[30];
int numPassengers;
};
#endif
This is the layout of my class Passenger:
#include <string>
#include "Date.h"
class Passenger
{
public:
//Part a)
// Constructor
Passenger(int = 1337, std::string = "Name", std::string = "Banana Island", std::string = "(514)514-5145", Date birth=(1,1,1999));
// Part b)
int getID();
std::string getName();
std::string getAddress();
std::string getTel();
Date getBday();
// Part c)
void setAddress(std::string);
void setTel(std::string);
void setBirthD(Date);
// Part d)
void printInfo()const;
private:
int ID;
std::string name;
std::string address;
std::string Tel;
Date birthD;
};
I'm trying to access the ID, an attribute of the Passenger object, which itself is and attribute of the Flight object. The passengers are all stored in an array called passengerList, it is 30 passengers long. In my main.cpp file, I've defined the remove passenger function as follows:
void Flight::removePassenger(int removeThisID) // Passing the ID to remove
{
for (int i = 0; i < 30; i++) // Check all the passengers in the array
{
// Unsure about the way to access the ID. PassengerList[i].ID == removeThisID ?
}
}
Unfortunately, you can't delete from an array, from what I understand of your project I can suggest you 2 things to overcome this problem
1 - You can store the array in some other data structure in every deletion, and reinitialize it without your target, which is a lot of work OR,
2 - You can use vectors from cpp's standart library (std) which will do the first part for you, automatically. You can check the vectors from http://www.cplusplus.com/reference/vector/vector/vector/
You can not remove from an array. Its fixed size.
One way would be to recreate the array everytime you change the size,
but that would be quite annoying.
Gladly there is the c++ standard library which you can use to solve
such problems.
It has a diverse set of containers that manage the storage space for their elements and provide member functions to access them.
Replace Passenger* passengerList[30] with std::vector<Passenger> passengerList
void Flight::removePassenger(int removeThisID) // Passing the ID to remove
{
for (unsigned int i = 0; i < passengerList.size(); i++)
{
// if (passengerList.at(i).getID() == removeThisID)
if (passengerList[i].getID() == removeThisID)
{
passengerList.erase(passengerList.begin()+i);
return;
}
}
}
I'm stuck on a homework question. We are to create a class template called department, and in the constructor, we need to initialize a counter to be used later. I'm having trouble understanding how to use this counter elsewhere in the program. We were provided with a main.cpp file to use, which we aren't allowed to change. These are the specific instructions I'm stuck on:
You are to create a constructor that may take the department name as an argument, and if it’s null it will ask for a department name to be entered from the keyboard and stores it. It also initializes a counter that keeps track of the number of employees in the array and is maintained when you add, remove, or clear.
The only way I've managed to get it to work is by setting the constructor to accept two arguments, one for department name, and one for the counter. But the main.cpp file provided only allows for one argument, name.
Department.h:
template <class Type>
class Department {
private:
std::string name;
...
public:
Department(const std::string & deptName)
{
int counter = 0;
name = deptName;
}
...
};
Main.cpp (provided, and not allowed to change):
int main()
{ Department dept1("CIS"); // a department
...
Is there a way to use the counter initialized in the constructor outside of the constructor without changing the argument requirements for Department?
Is there a way to use the counter initialized in the constructor outside of the constructor without changing the argument requirements for Department?
Sure. Make a counter member variable, and use it in the methods you write for your class.
template <class Type>
class Department {
private:
std::string name;
int counter;
public:
Department(const std::string & deptName)
{
counter = 0; // note `int` not needed, as counter is already declared
name = deptName;
}
int getCounter()
{
return counter;
}
void addEmployee(std::string name)
{
counter++;
// do something with adding employees
}
// other methods
};
I have this class people
class people {
public:
string name;
int balance;
people(string name, int newb) {
name = name;
balance = newb;
}
};
I thought I had a decent understanding of constructors until I couldn't figure out why this wouldn't work:
for(int i=0; i<users; i++) {
fin>>temp_name; // !!!!!
givers_list.push_back(temp_name, 0);
}
No error, only when I'm debugging I have a vector of users that all have names = "" and balance = 0; I am also 100% sure that temp_name is a string like "David"
Only when I make a temporary object, "cat", construct it, modify it's name, and then push_back does it work right:
for(int i=0; i<users; i++) {
fin>>temp_name; // !!!!!
people cat = people(temp_name, 0);
cat.name = temp_name;
givers_list.push_back(cat);
}
Why didn't it work the first time? I've checked SO and C++ forums and I believe they did what I did. Curiously, I'm sure the issue is regarding a string because when I say givers_list.push_back(people(temp_name, 50));, then the object would correctly have 50 as a balance (name is still "").
My background started with C++ and I've done Java for a long time but returning to C++ is a little alien. Sorry if this is a stupid mistake. I already finished and submitted the program I just don't know why the constructor doesn't work without a stent.
Let me know if this replicates for you.
The problem is that your constructor is incorrect.
Inside:
people(string name, int newb) {
name = name;
balance = newb;
}
name refers to the parameter name, not the class data member name.
To fix this, either qualify name with this, or directly construct name and balance, rather than default-constructing them and then assigning to them:
//Option 1:
people(string name, int newb) {
this->name = name;
balance = newb;
}
//Option 2: Preferred; avoids duplicate initialisation.
people(string name, int newb) :
name(name), balance(newb)
{
}
//Option 3: Optimal; avoids unnecessary copies.
people(string name, int newb) :
name(std::move(name)), balance(newb)
{
}
This line
name = name;
The compiler is using the parameter name for each part of this statement. This means it is assigning the parameter name to itself.
Change it to
this->name = name;
I am a newbie in C++ as I am learning it at college, and I have a problem. I have a project to do that should be fairly easy to do, but I seem to encounter some difficulties. I must implement a Person class, with exactly 3 arguments: name, firstnames (this is my BIG problem because there can be several names put in an array of char*, so it will be a char**) and age. My teacher gave me a testPerson.cc file in which it uses my Person class to create several types of Persons. My problem is when I create the constructor(s), because I must manage several cases: for example if a person has only one first name, for example:
const Personne lea ("Tralala", "Lea", 45);
or a person has several firstnames:
const char* prenoms1[] = {"Marcel", "Firmin", "Gaston", 0};
const Personne marcel ("Meharcele", prenoms1, 78);
I know for sure that I must have exactly 3 attributes: name(char*), firstname(char**), age(int).
Here is a snippet from the file that the teacher gave me(which I must respect when creating my Person class):
int main () {
cout << "We create the next persons:\n";
// version of constructor with several names:
const char* prenoms1[] = {"Marcel", "Firmin", "Gaston", 0};
const Personne marcel ("Meharcele", prenoms1, 78);
// version of constructor with only one name:
const Personne lea ("Tralala", "Lea", 45);
As you can see, I need several constructors for cases with only 1 fname, or several fnames
And here is my class:
#include "personne.h"
Personne::Personne(const char* name, const char** fnames, int a) {
nom = name;
prenom = fnames;
age = a;
}
Personne::Personne(const char* name, const char* fname, int a) {
nom = name;
prenom = fname; //here I have a problem, since the attribute prenom is of type char**
age = a;
}
void Personne::setAge(int& a) {
age = a;
}
void Personne::setNom(const char* name) {
nom = name;
}
void Personne::setPrenoms(const char** fnames) {
}
int Personne::getAge() const {
return age;
}
char* Personne::getNom() const {
return nom;
}
char** Personne::getPrenoms() const {
return prenom;
}
I spent hours and hours thinking about a solution, I googled a lot(so I did my homework), it's just that I do not know how to implement the right solution.
Some considerations:
a single first name can be seen as an array of one element so you can still use an array to internally store the list of first names, and let it be of size 1 when there is only one.
in your constructor you are assigning pointers which are allocated on stack in the caller of your constructor, while this doesn't create problems in your specific snipped, it isn't the right way to do it: you should create your own copy of each value of the person so that they don't get lost once the parameters are lost and manage their destruction in the Personne destructor ~Personne()
I don't know if you are allowed to use STL library, in that case consider using string to store names and vector<string> list of names, they will do most of the dirty work for you
This if for my homework.
I have a class called Student that takes 3 parameters (id, name, class) and I want to store each student in an array called Roster (which can only have 7 students).
The user will provides input to add or remove students. Thus, I have to manage the array by creating or deleting students. So if the user specify the student ID, I have to remove him for the array.
I tried to use a fixed array, but I'm struggling to make it works. Is there a better way to implement this?
I must not use a vector or any STL container.
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
static const int SIZE = 7;
class Student {
private:
int student_id;
std::string name;
std::string classification;
public:
Student(int, std::string, std::string); // constructor; initialize the list to be empty
~Student();
void print();
};
#endif
student.cpp
#include <iostream>
#include <string>
#include "student.h"
#define PROMPT "class> "
using namespace std;
Student::Student(int a, string b, string c){
student_id = a;
name = b;
classification = c;
}
Student::~Student(){
//delete Student
}
void Student::print(){
cout<<"Enrolled:"<<endl;
cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}
main.cpp
#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"
#define PROMPT "class> "
using namespace std;
//**** Implement Error Handling ****\\
enum errorType {
UNKNOWN_ERROR,
INPUT_ERROR,
HANDLER,
NUM_ERRORS
};
// error messages
string errorMessage[NUM_ERRORS] = {
"Unknown Error\n",
"Input Error\n",
};
// error handler
void handleError(errorType err) {
if(err > 0 && err < NUM_ERRORS)
cout<< "Error: "<< errorMessage[err];
else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}
//**** END Error Handling ****\\
void enroll(Student newStudent){
cout<<"test";
Student roster[SIZE];
for(int i=0;i<SIZE;i++){
newStudent->roster[i];
}
}
void handleInput() {
int id; string n, c;
cin>>id>>n>>c;
Student newStudent(id,n,c);
newStudent.print();
enroll(newStudent);
//cout<<"hello3"<<endl;
return;
}
int main() {
//Student newStudent; /* <-- why doesn't this work?!*/
string input = "";
bool finished = false;
cout<<PROMPT; // prompt the user
while(!finished) {
if(input!="") cout<<PROMPT;
cin>>input;
if(input=="enroll") {
cout<<PROMPT<<"Enroll student:"<<endl;
handleInput();
}
else if(input=="drop") {
cout<<PROMPT<<"Enter ID:"<<endl;
}
else if(input=="roster") {
cout<<"This will print formatted list of students"<<endl;
}
else if(input=="quit") {
finished=true;
}
else handleError(errorType(1));
}
}
Since it is a homework, I'd like to point out some mistakes you did because it is important to understand what you are doing in the first place.
You must not program by coincidence, but by trying to understand exactly what's going on. By doing that you will become better and better and the answers should fall in place.
What you've done
So, from what you are describing, the array is fixed. Thus it is a good idea to use a constant as you did (SIZE).
However, as we can see below you a declaring an array of size SIZE in the function. By doing that, your array is like a temporary variable, because its scope is inside the function. Each time you call this function, the array will be declared again and then deleted at the exit. So it should be declared outside.
void enroll(Student newStudent)
{
cout<<"test";
Student roster[SIZE]; // Here 'roster' will be available only inside the function.
for(int i=0;i<SIZE;i++)
{
newStudent->roster[i]; // Here there is few mistakes see my explanation below*
}
}
If we look at this part:
newStudent->roster[i];
First of all, the arrow '->' is used with pointers. The dot '.' is used with objects. In both case, it does the same thing, access to public members of Student.
Since you passed
void enroll(Student newStudent)
you should use '.' instead.
newStudent.SomeOfYourMembers;
If the parameter was a pointer to a Student
void enroll(Student *newStudent)
Then, you'd have to use the arrow '->' like you did.
Back to the original statement:
newStudent->roster[i];
This means, you want to access to 'roster' array at position 'i' inside your Student object (newStudent). As you can see in your code, roster is not declared inside Student (and should not be since you want an array of Students), so that won't work.
Guidelines
As I mentionned, your array should be outside the function, so at a higher scope.
Then, if you need an array of student, basically, 'roster[i]' will give you access to the student 'i'. Thus, if you want to print the student, you would do something like that:
roster[i].print();
This would be valid because 'print()' is defined as public.
In order to store a student inside the array, you can do something like:
roster[i] = new Student(0 /* id*/, "name", "classification");
But don't forget, each time you use new, you have to balance it with a delete. And if you are creating the student like this in a loop, you will have to clean them the same way:
for(int i = 0; i < SIZE; ++i)
{
delete roster[i];
}
Good luck!
Don't hesitate if there is there anything that I could clarify. I hope this helps!
Edit: In reply to your first comment.
Concerning the roster array
No, it is not mandatory to create a class roster you could declare roster in the main.cpp.
The key concept is that by defining
Student roster[SIZE];
the array will contains objects of type Student.
What roster[i].print() means is that you are printing one of the Student of that array, in fact the one at position 'i'.
Concerning the print() function
What is powerfull with Object Oriented language, each object will have the same print() function. So, you do not need to convert the array to string.
However, if you want a string to be printed out (or returned) you can write the code inside the print() function that will do this job.
The advantage of this, is that if further on you need to change your array in some ways, your print() function will always work.
Concerning the Delete
When you are doing something like this on an array that contains objects:
delete roster[i];
It will delete the object at the position 'i'. Thus, the destructor of that Student 'i' will be called. If your object Student would contains other object, you would have to delete them in the destructor.
Further notices
Since ID is an input that you are storing into a string, you will have to convert the ID to the same type of the student_id, which is a int. Then you can always write a loop for each student and check their ID to delete the proper one.
Concerning the container, a fixed array might not be the best to achieve this job. You might want to look the LinkedList concept.
It doesn't make much sense for enroll to be a member function, so
I'd wrap the roster into a class to get automatic clean up of my
pointers.
#include <cstddef>
struct Student {};
class Roster
{
private:
static const size_t size = 7;
// non-copyable
Roster(const Roster&);
Roster& operator=(const Roster&);
public:
Roster() {
for(unsigned i = 0; i < size; ++i) {
roster_[i] = NULL;
}
}
~Roster() {
for(unsigned i = 0; i < size; ++i) {
delete roster_[i];
}
}
// enroll by copy
bool enroll(const Student& s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = new Student(s);
return true;
}
}
// out of space
return false;
}
// enroll by taking ownership
bool enroll(Student* s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = s;
return true;
}
}
// out of space
return false;
}
private:
// data
Student* roster_[size];
};
int main()
{
Roster r;
Student s;
r.enroll(s);
Student* sp = new Student();
r.enroll(sp);
return 0;
}
What about this?
Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");
Ps:
Enrol and Size shouldn't be members of the student class.
Print should ideally be externalized and a ToString function should be added instead.
You should use the inline constructor initialization instead:
Student(int a,string b,string c):id(a),name(b),class(c){}
You've used the keyword class as a variable name of type string. You shouldn't do that. Does it even compile like that?
enroll should have two arguments: void enroll( Student enrollee, Student Roster[]). You should probably change the name of Roster to roster because it's not a class and typically class names are capitalized.
If your array will only ever have 7 students then you could use some sentinel value to mark that the current student as an invalid student. Perhaps the id will be -1 to mark this. It means basically that you need some way to keep track of which spots in the array you can still use. If you don't do this then declaring an array of Students will get you an array of students with garbage member variables. You wouldn't be able to tell which students are real ones and which are just place holders for when someone new enrolls in the class. I would create a default constructor of Student and initialize its member variables like this:
id=-1;
name="";
name_of_class="";
I changed the name of your string class to avoid confusion.
After all that, enroll would look something like this:
void Student::enroll( Student enrolee, Student roster[]){
//search through roster to check for the first student with an
//id of -1
//if there are no students with id of -1, produce an error message
//that the class is full
//overwrite the student with id of -1 with the id, name, and
//name_of_class of enrollee
}
Although I'm not sure what exactly string class is there for. Does it store what class the Student is in? Is it their year in school like Freshman, Sophomore?
If you're suppose to use dynamic allocation of roster, though, it's a different story, but you said it will only ever have seven students.