Unable to access member function in a vector of objects - c++

I am trying to simply create a vector of objects, add an object to it, and then display some variables in that object in the vector by accessing the function "getter's". Code compiles but it shows nothing for functions that return string and a garbage number for the ones that return double. I am sure it is something simple....can you help (assignment due in a couple of hours :S)?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Employee
{
string fName, lName;
double weeklyIncome, grossSales, bonus;
public:
Employee(){};
Employee(string fn, string ln, double sales)
{
fName = fn;
lName = ln;
grossSales = sales;
bonus = sales * 0.09;
weeklyIncome = 200;
}
double getNetIncome() {return bonus + weeklyIncome;}
string getfName() {return fName;}
double getgrossSales() {return grossSales;}
~Employee(){};
};
int main()
{
vector<Employee> salespeople(15);
Employee e1("John", "Smith", 5000);
salespeople.push_back(e1);
cout << salespeople[0].getNetIncome();
cout << salespeople[0].getgrossSales();
cout << salespeople[0].getfName();
system("pause");
return 0;
}

vector<Employee> salespeople(15); // This creates a vector of 15 elements
Employee e1("John", "Smith", 5000);
salespeople.push_back(e1); // Now you have added the 16-th element
cout << salespeople[0].getNetIncome(); // The first element is still the default
// constructed element.
cout << salespeople[0].getgrossSales();
cout << salespeople[0].getfName();
You can fix the problem by using
vector<Employee> salespeople; // Create an empty vector and then
// add items to it.
or by changing
salespeople.push_back(e1);
to
salespeople[0] = e1;
Suggestion for improvement
Change the default constructor to initialize the double variables to sane values.
Employee() : weeklyIncome(0.0), grossSales(0.0) bonus(0.0) {};

Related

Why is my elements in my vector of objects not updating upon calling one of the objects member function?

I have been trying to do debug this for a long time using visual studio debugger but I can't figure out why my function emp.setHoursWorked(hWorked); in recordHoursWorkedForEmployee only seems to be update numOfHoursWorked while in recordHoursWorkedForEmployee, as soon the program exits the function the numOfHoursWorked of all Employees in the vector go back to 0. Below is the code in question. Any help would be appreciated.
#ifndef PAYROLLSYSTEM
#define PAYROLLSYSTEM
#include "Employee.h"
#include "Paycheck.h"
#include <string>
#include <vector>
using namespace std;
class PayRollSystem
{
public:
//custom constructor gets company name
PayRollSystem(string);
void createEmployee(string, string,string, double);
void removeEmployee(string);
void recordHoursWorkedForEmployee(string);
void issuePaychecks();
private:
string companyName;
vector<Employee> companyEmployees;
};
#endif
void PayRollSystem::createEmployee(string empId, string fName, string lName, double hWage)
{
Employee temEmp = Employee(empId, fName, lName, hWage);
companyEmployees.push_back(temEmp);
}
void PayRollSystem::recordHoursWorkedForEmployee(string empId)
{
for (Employee emp : companyEmployees)
{
if (emp.getEmployeeId() == empId)
{
int hWorked = 0;
cout << "What are the hours the worked for " + emp.getEmployeeId() + " during current pay period?" << endl;
cin >> hWorked;
//TODO: For some reason this line is not updating the hours worked. Must fix!
emp.setHoursWorked(hWorked);
cout << "Hours for " + emp.getEmployeeId() + " have been changed to " << emp.getHoursWorked() << endl;
}
}
}
I excluded the header file here in order to not paste too many things not relevant to the problem i'm facing, only implementations of member functions relevant to the problem provided
//Overloaded constructor to be used with PayRollSystem
Employee::Employee(string empId, string fName, string lName, double hWage)
{
employeeId = empId;
firstName = fName;
lastName = lName;
hourlyWage = hWage;
numOfHoursWorked = 0;
}
void Employee::setHoursWorked(int hWorked)
{
if (hWorked >= 0)
numOfHoursWorked = hWorked;
else
{
cout << "Invalid number of hours worked." << endl;
exit(EXIT_FAILURE);
}
}
string Employee::getEmployeeId() const
{
return employeeId;
}
This line makes a copy of each employee:
for (Employee emp : companyEmployees)
The variable emp is a copy of the object in the container. So if you update this you are only updating the copy. Each iteration you get a new value copied into emp but any changes are not reflected in the original object.
You probably meant:
for (Employee& emp : companyEmployees)
^^^
Here emp is a reference to the object inside the vector. If you modify this you are modifying the original value inside the vector.

C++ How to properly access dynamic array elements using class method

I've created a class Student which contains a dynamic array. I've filled the first two items with the constructor. Every method I've tried to use to access/print those two elements from the main get a read/access violation and crashes. I've added a cout in the constructor that shows the elements ARE filled and exist. I've included two failed methods in the main: A void function that attempts to send first element to cout, and a method that accepts an int for the desired index. Both have been commented out to allow a test run showing elements are created and printed by the constructor.
Header:
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
#include <iostream>
#define ARRAY_MAX 15
using namespace std;
class Student
{
private:
string firstName, lastName;
unsigned int ID, numItems = 0;
typedef string* StringPtr;
StringPtr items;
public:
int capacity = 15;
Student();
Student(const string fName, const string lName, const unsigned int id);
string getfName() const;
string getlName() const;
void getItem(int num);
string getItemB(int num) const;
unsigned int getID() const;
};
#endif // STUDENT_H
Definitions:
#include "student.h"
using namespace std;
Student::Student()
{
}
Student::Student(const string fName, const string lName, const unsigned int id)
{
firstName = fName;
lastName = lName;
ID = id;
StringPtr items = new string[capacity];
numItems = 0;
items[0] = "stuff";
items[1] = "things";
cout << items[0] << endl << items[1] << endl;
}
string Student::getfName() const
{
return firstName;
}
string Student::getlName() const
{
return lastName;
}
void Student::getItem(int num)
{
cout << items[0] << endl;
}
string Student::getItemB(int num) const
{
return items[num];
}
unsigned int Student::getID() const
{
return ID;
}
Main:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include "student.h"
using namespace std;
int main()
{
Student stu;
string str;
stu = Student("John", "Smith", 1200);
cout << stu.getfName() << " " << stu.getlName() << endl;
//stu.getItem(0);
//cout << stu.getItemB(0);
system("pause");
// Quit without error
return 0;
}
Solution
Change
StringPtr items = new string[capacity];
into
items = new string[capacity];
TL;DR
In
Student::Student(const string fName, const string lName, const unsigned int id)
{
firstName = fName;
lastName = lName;
ID = id;
StringPtr items = new string[capacity];
numItems = 0;
items[0] = "stuff";
items[1] = "things";
cout << items[0] << endl << items[1] << endl;
}
The line
StringPtr items = new string[capacity];
creates a new Automatic (local) variable items and initializes it rather than the intended private member variable StringPtr items;. This is commonly known as Variable Shadowing. The local items goes out of scope at the end of the function leaking the allocated memory and the member items is never initialized leading to stu.getItem(0); accessing an uninitialized pointer and triggering the crash.
void Student::getItem(int num)
{
cout << items[0] << endl; // items points Crom knows where, so items[0] is invalid.
}
This crash is quite fortunate. Accessing an unitintialized pointer results in Undefined Behaviour which means it could do anything from looking like it works to causing the universe to explode.
The next problem you have to deal with is observing The Rule of Three.
The best way to deal with this is std::vector
std::vector<string> items;
std::vector is Rule of Three (Rule of Five, actually) compliant so that you don't have to be.
If std::vector is not allowed, you need to implement a copy constructor
Student::Student(const Student & src):
firstName(src.firstName), lastName(src.lastName),
ID(src.ID), numItems(src.numItems),
items(new string[capacity])
{
for (int i = 0; i < src.numItems; i++)
{
items[i] = src.items[i];
}
}
and an assignment operator (Taking advantage of the Copy and Swap Idiom for simplicity)
Student & Student::operator=(Student src)
{
swap(*this,src);
return *this;
}
Writing swap I'll leave up to you.

Whats wrong with my class [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I don't know why but when i create an object with my class and use the default constructor, when i try to pass the variable named cash to the accessor user2.setCash(cash) which purpose is to primary set cash equal to new_cash, it gives a large value like 1.222256e+461 or something like that. Why does that happen? If i use my overload constructor it works fine.
main.cpp
#include <iostream>
#include <string>
#include "Bank.h"
using namespace std;
int main()
{
string name;
int id;
double cash;
bank user2;
cout << "\n\nPlease type your name: ";
getline(cin >> ws, name);
user2.setName(name);
cout << "Enter an id number: ";
cin >> id;
user2.setID(id);
cout << "Enter your cash: ";
cin >> cash;
cout << cash << endl;
user2.setCash(cash);
cout << "\nAlright " << user2.getName() << ", current cash: " << user2.getCash();
cout << "\nChoose how much would you like to Deposit: ";
cin >> cash;
user2.deposit(cash);
cout << "New amount is: " << user2.getCash() << " For user ID: " << user2.getID() << "\n\n";
bank::printStatic();
return 0;
}
Bank.h
#ifndef BANK_H
#define BANK_H
#include <iostream>
#include <string>
using namespace std;
class bank
{
public:
// Default Constructor
bank();
// Overload Constructor
bank(string, int, double);
// Destructor
~bank();
// Accessor Functions
string getName() const;
int getID() const;
double getCash() const;
// Mutator Functions
void setName(string);
void setID(int);
void setCash(double);
// Functions
void withdraw(double);
void deposit(double);
static void printStatic();
private:
// Member Variables
string new_name;
int new_id;
double new_cash;
// Static Member Variables
static int num_of_accounts;
static double total_cash;
};
#endif
Bank.cpp
#include "Bank.h"
// Static Variables
int bank::num_of_accounts = 0;
double bank::total_cash = 0.0;
// Default Constructor
bank::bank()
{
int new_id = 0;
double new_cash = 0.0;
++num_of_accounts; // New object is created e.g. a person so total accounts must be increased.
}
// Overload Constructor
bank::bank(string name, int id, double cash)
{
new_name = name;
new_id = id;
new_cash = cash;
++num_of_accounts; // New object is created e.g. a person so total accounts must be increased.
total_cash += new_cash; // New object is created e.g. a person so his/hers cash must be added to the total cash of the bank.
}
// Destructor
bank::~bank()
{
--num_of_accounts; // When Destructor is called to destroy an object (e.g. a person) then the id must be dropped by 1 cause the person e.g. (left).
total_cash -= new_cash; // And the balance he had to be removed so it is not counted in total cash avaliable in the bank cause he e.g. (left).
}
// Accessor Functions
string bank::getName() const
{
return new_name;
}
int bank::getID() const
{
return new_id;
}
double bank::getCash() const
{
return new_cash;
}
// Mutator Functions
void bank::setName(string name)
{
new_name = name;
}
void bank::setID(int id)
{
new_id = id;
}
void bank::setCash(double cash)
{
cout << new_cash << endl;
total_cash -= new_cash; // We must remove his prior cash which we holded in the total so we can then use the new value suplied.
new_cash = cash;
total_cash += new_cash; // Here we add the new cash (balance) he/she has.
}
void bank::withdraw(double cash)
{
new_cash -= cash;
total_cash -= cash;
}
void bank::deposit(double cash)
{
new_cash += cash;
total_cash += cash;
}
void bank::printStatic()
{
cout << "Total users are: " << num_of_accounts << endl;
cout << "Total cash in bank is: " << total_cash << endl;
}
You need to initialize all primitive type members in the constructor.
Otherwise you get indeterminate values
Also, the non-default constructor is buggy:
// Default Constructor
bank::bank()
{
int new_id = 0;
double new_cash = 0.0;
....
^ sets values of local variables, not the member variables
I'd suggest to use the initilization lists:
// Default Constructor
bank::bank() : new_name(), new_id(0), new_cash(0.0)
{
++num_of_accounts;
}
// Overload Constructor
bank::bank(string name, int id, double cash)
: new_name(name), new_id(id), new_cash(cash)
{
++num_of_accounts;
total_cash += new_cash;
}
You could also combine the two:
bank::bank(string name = "", int id = 0, double cash = 0.0)
: new_name(name), new_id(id), new_cash(cash)
{
++num_of_accounts;
total_cash += new_cash;
}
In your default constructor, you're declaring local variables with the same names as the member variables. Then you're setting these local variables instead of assigning the members. Get rid of the type declarations so they're normal assignments.
bank::bank()
{
new_id = 0;
new_cash = 0.0;
++num_of_accounts; // New object is created e.g. a person so total accounts must be increased.
}

Passing a class object to a list table

I have a struct list, a class castomer. I want to store my castomer to the list. For that I am creating a castomer each time and I strore them to a list table. There are no errors except that the program crashes each time I try to store a castomer into my table.
I have this list and class:
class castomer{
private:
string name;
string lastname;
int number;
double time;
public:
void setAll(string,string,int,double);
int numberR(){return number;}
double timeR(){return time;}
void displayAll();
};
struct node {
castomer person;
struct node *next;
};
This function for adding castomer:
void add(clock_t *start,struct node *table[])
{
*start = clock();
double time=(double)*start;
int i=0;
while(table[i]!=NULL)
{
i++;
}
if(i > 24)
cout << "We are not able to add another castomer becase we are full please wait for ont to go "<<endl;
else{
castomer c1;
cout<<i;
cout<< "Give me the castomers name and lastname :";
string temp1,temp2;
cin>>temp1;
cin>>temp2;
c1.setAll(temp1,temp2,i,time);
table[i]->person=c1;//my program crases here anyone knows why?
}
}
ps: In my main the table[] looks like this struct node * table[25];
struct node* table[25]
This is declaring table to be an array of 25 pointers. You have to allocate memory for each of these pointers which from looking at your code is missing.
After your while-loop, table[i] will be NULL.
table[i]->person = c1; // Your program crashes here because of that.
Using your code as it is, you should do
table[i] = new node;
table[i]->person = c1;
But the code looks very strange, like you want to implement a linked list (the node structure) but are sticking to using arrays for some reason.
If you're aiming for a linked list, you need to rethink a lot of your code.
If you're not, you can lose the node type completely.
Since you are using (or trying to use) C++ I will make mention of a few things you can do to improve your code and make your own life easier.
In C++ you can define constructors for initializing objects.
Your function setAll is a bad practice. You don't really want to change all data of a person after you have created. You just want to initialize the data at creation time. Well use constructors.
You don't need pointers
For what you want to do you don't need complicate the code using pointers you could pass the arguments by reference.
You are using C++, use STL
Specifically vector I guarantee it, will help you.
Use cout << for displaying yuor object
you could add a friend ostream& operator<< function to your class in order to be able to write code like:
Customer a;
cout << a << endl;
A complete example:
#include <iostream>
#include <vector>
#include <ctime>
#include <string>
using namespace std;
class Customer
{
public:
Customer(){} // default constructor.
Customer(string pname, string plastname): name(pname), lastname(plastname)
{
id = ++idgen; // Set an id number.
time = (double)clock(); // initialize time.
}
int getId() {return id;} // former numberR().
double getTime() {return time;} // former timeR().
friend ostream& operator<<(ostream &out, Customer obj)
{out << obj.name << " " << obj.lastname << ". " << "Id: " << obj.id << " Time: " << obj.time;}
private:
static int idgen; // static values are a good way for keep some sort of id.
int id; // former member: number.
double time; // Why don't use clock_t directly?
string name, lastname;
};
int Customer::idgen = 0; // Initialize static variable.
int main()
{
int const MAX_NUMBER_PERSONS = 2;
std::vector<Customer> customer_list;
string name, lastname;
while (customer_list.size() < MAX_NUMBER_PERSONS)
{
cout << "Give me the castomers name and lastname <name> <lastname>:";
cin >> name >> lastname;
customer_list.push_back(Customer(name, lastname));
}
for (auto &x: customer_list) // If you're learnign C++ its a good moment for search
{ // for c++11 doc.
cout << x << endl;
}
return 0;
}

Compiler not interpreting well pointers to string literals as arguments for a method

noob here. Having a doubt while doing an exercise from a book.
The doubt is the following: Why if I use a const std::string * as an argument to a method, the compiler sends me the following error: no matching function for call to 'BankAccount::define(const char [11], const char [11], int)' in the client?
If I swap the prototype and definition of the method to accept as an argument a const std::string & (like I did in the constructor) it's no problem for the compiler.
Client:
// usebacnt.cpp --
#include "BankAccount.h"
#include <iostream>
int main()
{
BankAccount john;
BankAccount mary("Mary Wilkinson", "5000000000"); // balance set to 0 because of default argument
john.display();
mary.display();
john.define("John Smith", "4000000000", 26); // error line
mary.deposit(1000.50);
john.withdraw(25);
john.display();
mary.display();
std::cin.get();
return 0;
}
Class declaration:
// BankAccount.h -- Header file for project Exercise 10.1
#ifndef BANKACCOUNT_H_
#define BANKACCOUNT_H_
#include <string>
class BankAccount
{
private:
std::string fullName;
std::string accountNumber;
double balance;
public:
BankAccount(); // default constructor
BankAccount(const std::string &fN, const std::string &aN, double b = 0.0); // constructor with a default argument
void display() const;
void deposit(double amount);
void withdraw(double amount);
void define(const std::string *pfN, const std::string *paN, double b);
};
#endif
Class implementation:
// methods.cpp -- Compile alongside usebacnt.cpp
#include "BankAccount.h"
#include <iostream>
void BankAccount::display() const
{
using std::cout;
using std::ios_base;
ios_base::fmtflags orig = cout.setf(ios_base::fixed, ios_base::floatfield); // formatting output and saving original
cout.precision(2);
cout << "Full Name: " << fullName << '\n';
cout << "Account Number: " << accountNumber << '\n';
cout << "Balance: " << balance << "\n\n";
cout.setf(orig);
}
void BankAccount::deposit(double amount)
{
if (amount < 0)
{
std::cout << "You can't deposit a negative number! Amount set to zero.";
amount = 0;
}
balance += amount;
}
void BankAccount::withdraw(double amount)
{
if (amount < 0)
{
std::cout << "You can't withdraw a negative number! Amount set to zero.";
amount = 0;
}
if (balance < amount)
{
std::cout << "You can't withdraw more money than you have. Amount set to zero.";
amount = 0;
}
balance -= amount;
}
void BankAccount::define(const std::string *pfN, const std::string *paN, double b)
{
fullName = *fN;
accountNumber = *aN;
balance = b;
}
// constructors
BankAccount::BankAccount() // default constructor
{
fullName = "empty";
accountNumber = "empty";
balance = 0.0;
}
BankAccount::BankAccount(const std::string &fN, const std::string &aN, double b) // constructor with default argument
{
fullName = fN;
accountNumber = aN;
balance = b;
}
Shouldn't the compiler interpret the literal as a string object (like it does with the reference)? So if I say it's a pointer it should pass the address of the string (its first element).
Any help?
Shouldn't the compiler interpret the literal as a string object (like it does with the reference)?
No. Pointers are not references; smack anyone who tells you that they are.
It all comes down to this: std::string is not a string literal. Therefore, when you pass a string literal to a function that takes a std::string, a temporary std::string that holds the contents of the literal must be created. This is done with the conversion constructor of std::string.
A const& is allowed to be initialized from a temporary, which allows conversion constructors to work their magic. A const* must be a pointer, and you're not supposed to get pointers to temporaries. Therefore, const* cannot be magically filled in by a temporary created from a conversion constructor.
You should use a const std::string & instead of a pointer. Or a std::string value if you have C++11 move constructors available.