Employee Test Driver Data Structures - c++

What would I use to define these Variables outside the Public and Private? Enum?
The Instructions for this section are this:
A default constructor. Remember that the default constructor for Address has the following initial values: Address to "99999 Sunset Boulevard" , "Beverly Hills", "CA", "99999"
4 private string instance variables for :Street, City, State, Zip
A constructor with 4 parameters: one for street, one for city, one for state, one for zip.
A printAddress(): it prints the Street, City, State, and Zip
Here is what I got so far
class Address
{
public:
Address();
Address(City defaultCity, State defaultState, Street defaultStreet, Zip, defaultZip);
int getCity();
int getState();
int getStreet();
int getZip();
int printAddress();
private:
int Street, City, State, Zip;
};
Address :: Address(City defaultCity, State defaultState, Street defaultStreet, Zip, defaultZip);
{
defaultCity = City
defaultState = State
defaultStreet = Street
defaultZip = Zip
}
Address::Address()
{
Street = "99999 Sunset Boulevard,";
City = "Beverly Hills,";
State = "CA,";
Zip = "99999";
}
int Address::getCity()
{
return City;
}
int Address::getState()
{
return State;
}
int Address::getStreet()
{
return Street;
}
int Address::getZip()
{
return Zip;
}
int Address::printAddress()
{
return Street, City, State, Zip;
};
Also when he says "print" I assume he means display right?
Thank you

I would do it like this:
#include <iostream>
#include <string>
/********************
* File: Main.cpp *
********************/
/*
* For simplicity I put it all in one file.
*/
class Address
{
public:
explicit Address();
explicit Address(const std::string& city, const std::string& state,
const std::string& street, const std::string& zip);
const std::string& getCity() const;
const std::string& getState() const;
const std::string& getStreet() const;
const std::string& getZip() const;
void printAddress() const;
private:
std::string street;
std::string city;
std::string state;
std::string zip;
};
// Default Constructor
Address::Address() :
city("Beverly Hills"),
state("CA"),
street("99999 Sunset Boulevard"),
zip("99999")
{ }
Address::Address(const std::string& city, const std::string& state,
const std::string& street, const std::string& zip) :
city(city), state(state), street(street), zip(zip)
{ }
const std::string& Address::getCity() const
{
return city;
}
const std::string& Address::getState() const
{
return state;
}
const std::string& Address::getStreet() const
{
return street;
}
const std::string& Address::getZip() const
{
return zip;
}
void Address::printAddress() const
{
std::cout << street << ", " << city << ", "
<< state << ", " << zip << std::endl;
};
int main(int argc, char* argv[]) {
Address defaultAddress;
defaultAddress.printAddress();
Address customAddress("Cologne", "NRW", "Domplatz 1", "D-50668");
customAddress.printAddress();
return 0;
}
EDIT:
Explaining some changes.
Look at the private section of the class declaration. You declared members as int although they should be strings. I corrected that.
In the constructors you should use initialization lists to initialize members.
In your constructor parameter list you used the words City, State, Street and Zip as if they were types. Which they are not. The type of these parameters is std::string. Or in my case I chose const std::string& because I prefer passing by reference over passing by value if both are viable.
If methods do not change the object you may declare them const so they can be called also on const instances of the class or const references. I did so in this example when declaring the getters.
I did not see a need to return anything to the caller after printing so I changed the return type to void.
I added a main function to test the class.
There is probably a lot more to say about the differences, but I think this is enough for tonight.
Cheers!

Related

Is it ideal to put data inside a private class? (C++)

For example, I have this class:
struct bankingFunctionality
{
private:
class bankingData
{
public:
int phoneNum, citizenNum, age, ID;
string name, address;
bankingData* next = nullptr;
};
public:
void input(bankingData*);
void firstUser();
void update(bankingData*);
};
Is it ideal to put the data class in private to "protect" data? Since the only way, I can think of how to access it for input and output is to have functions like void input(...) in public. However, every time I want to call input I would need to create a new object and waste memory.
If you're using this as a way to pass in arguments it's really wasteful and you should consider the traditional getX() and setX() approach for accessors and mutators. You can make these easy to use in a chain style if you return *this at the end of each.
As in:
class bankingData {
int phoneNum, citizenNum, age, ID;
string name, address;
bankingData* next = nullptr;
int getPhoneNum() const { return phoneNum; };
bankingData& setPhoneNum(int n) { phoneNum = n; return *this; };
const std::string& getName() const { return name; };
bankingData& setName(const std::string& n) { name = n; return *this; };
};
Where you can then do:
bankingData bd;
bd.setPhoneNum(111).setName(...);

Need help understanding the syntax of C++ Classes

I've done the Harvard CS50 Course and worked with python a fair bit. I'm now doing a C++ course (Microsoft's) and the learning exercise has me creating a few classes. The exercise specifically tasks me to instantiate a few objects in main and return some values;
#include <iostream>
#include "School.h"
int main()
{
Student student1("Joe", "Bloggs", 31, "123 Fake Street", "London");
Student student2("Fred", "Adams", 24, "95 Something Avenue", "Manchester");
Student student3("John", "Doe", 90, "44a Old Man Lane", "Kettering");
Course course1("Introduction to Psychology");
course1.addStudent(student1);
course1.addStudent(student2);
course1.addStudent(student3);
Teacher teacher1("Helen", "Professorson", 48, "15 Teacher Way", "Kent");
course1.addTeacher(teacher1);
std::cout << course1.getCourseName() << std::endl;
teacher1.GradeStudent();
}
I'm using a header file and cpp file to define the classes, School.h:
#pragma once
#include <string>
class Person
{
public:
// Constructors and Destructors
Person();
Person(std::string, std::string); // First and Last Name
Person(std::string, std::string, int, std::string, std::string, std::string); // fName, lName, Age, Address, City, Phone
~Person();
// Member functions
std::string getFirstName();
void setFirstName(std::string);
std::string getLastName();
void setLastName(std::string);
int getAge();
void setAge(int);
std::string getAddress();
void setAddress(std::string);
std::string getCity();
void setCity(std::string);
std::string getPhone();
void setPhone(std::string);
private:
std::string _fName;
std::string _lName;
int _age;
std::string _address;
std::string _city;
std::string _phone;
};
class Student : public Person
{
public:
// Constructors and Destructors
// Member Functions
void SitInClass();
};
class Teacher : public Person
{
public:
// Member Functions
void SitInClass();
void GradeStudent();
};
class Course
{
public:
// Constructors and Desctructors
Course();
Course(std::string); // course name
~Course();
// Member functions
void addStudent(Student);
void addTeacher(Teacher);
// Getters and Setters
std::string getCourseName();
void setCourseName(std::string);
private:
// Member variables
std::string _courseName;
Student _students[30];
Teacher _teacher;
};
School.cpp:
#include "School.h"
#include <iostream>
#include <string>
// Constructors
Person::Person()
{
std::string _fName{};
std::string _lName{};
int _age{};
std::string _address{};
std::string _city{};
std::string _phone{};
}
Person::Person(std::string fName, std::string lName)
{
std::string _fName{ fName };
std::string _lName{ lName };
int _age{};
std::string _address{};
std::string _city{};
std::string _phone{};
}
Person::Person(std::string fName, std::string lName, int age, std::string address, std::string city, std::string phone)
{
std::string _fName{ fName };
std::string _lName{ lName };
int _age{ age };
std::string _address{ address };
std::string _city{ city };
std::string _phone{ phone };
}
// Destructor
Person::~Person()
{
}
std::string Person::getFirstName()
{
return this->_fName;
}
void Person::setFirstName(std::string fName)
{
this->_fName = fName;
}
std::string Person::getLastName()
{
return this->_lName;
}
void Person::setLastName(std::string lName)
{
this->_lName = lName;
}
int Person::getAge()
{
return this->_age;
}
void Person::setAge(int age)
{
this->_age = age;
}
std::string Person::getAddress()
{
return this->_address;
}
void Person::setAddress(std::string address)
{
this->_address = address;
}
std::string Person::getCity()
{
return this->_city;
}
void Person::setCity(std::string city)
{
this->_city = city;
}
std::string Person::getPhone()
{
return this->_phone;
}
void Person::setPhone(std::string phone)
{
this->_phone = phone;
}
void Student::SitInClass()
{
std::cout << "Sitting in main theater" << std::endl;
}
void Teacher::SitInClass()
{
std::cout << "Sitting at front of class" << std::endl;
}
void Teacher::GradeStudent()
{
std::cout << "Student Graded" << std::endl;
}
Course::Course()
{
Student* _students;
Teacher* _teacher;
std::string _name{};
}
Course::Course(std::string name)
{
Student* _students[30];
Teacher* _teacher;
std::string _name{ name };
}
Course::~Course()
{
}
void Course::addStudent(Student student)
{
// TODO: Loop through _students and insert new student in
}
void Course::addTeacher(Teacher teacher)
{
this->_teacher = &teacher;
}
std::string Course::getCourseName()
{
return this->_name;
}
void Course::setCourseName(std::string name)
{
this->_name = name;
}
I actually haven't been taught inheritance yet, but since both Student and Teacher needed the same variables (name, age, address etc.) I decided it'd be sensible.
Having a few problems though:
My instantiations of Student and Teacher in main.cpp aren't correct. I think because they are inheriting from Person(?). How do I create a constructor within these derived classes? I googled this but the solutions didn't seem to work.
The Course Class requires an array of Students. Do I have to specify a size of the array in the header file? It seems silly that I've specified 30 in both the header file and the cpp file, but VSstudio complains if I don't.
I'm using strings here. I have previously learned from a different course about char* and memory regarding strings. How many chars are assigned to all of these string class variables? If I instantiate a Students with name "Joe" and then want to later change his name to "Joseph" using student1.SetFirstName, is that going to cause segmentation faults?
Thanks, I figured it out mostly...
I needed to create constructors in Student and Teacher with the same input variables as the Person class, and then call the Person constructor in the Student consturctor:
Student::Student()
{
}
Student::Student(std::string fName, std::string lName)
: Person(fName, lName)
{
}
Student::Student(std::string fName, std::string lName, int age, std::string address, std::string city, std::string phone)
: Person(fName, lName, age, address, city, phone)
{
}
You do not need to specify array size in the constructor:
Header file looks like this:
class Course
{
...
private:
// Member variables
std::string _name;
Student* _students[30];
Teacher* _teacher;
};
And the constructor looks like this:
Course::Course()
: _students{ 0 }, _teacher{ 0 }, _name{}
{
}
To initialise every array item to 0.
Not so sure on still...

C++ strings not working [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I would like to make this programm show the "Gianna" "Maria" and "M" strings on the screen but I can't. There's no error so I guess there's something wrong with my programm. Any suggestions what could fix my programm?
#include <iostream>
#include <string>
using namespace std;
class name
{
string fName, mName, sName;
public:
name (string fName, string mName, string sName){};
void setFName (string fName);
void setMName (string mName);
void setSName (string sName);
string getFName() const {return fName;}
string getSName() const {return sName;}
string getMName() const {return mName;}
friend ostream & operator <<(ostream &, const name &);
};
ostream& operator<<(ostream& os, const name& n) {
return os << n.fName << " " << n.sName<< " " << n.mName;
}
int main ()
{
name myName ("Gianna", "Maria", "M");
cout<<myName.getFName()<<" "<<myName.getMName()<<" "<<myName.getSName()<<endl;
return 0;
}
Your constructor:
name (string fName, string mName, string sName){};
doesn't do anything. You need to use the parameters to initialise your member variables.
name (string f, string m, string s)
: fName(f), mName(m), sName(s) {}
You forgot to initialize daya members of the class in the constructor.
Define the constructor the following way
name( const string &fName, const string &mName, const string &sName )
: fName( fName ), mName( mName ), sName( sName )
{
}
Correspondingly these member functions should be defined like
void setFName ( const string &fName)
{
this->fName = fName;
}
void setMName (const string &mName)
{
this->mName = mName;
}
void setSName (const string &sName)
{
this->sName = sName;
}
There is no need to make the operator << as a friend function of the class. It can be defined like
ostream& operator <<( ostream& os, const name& n ) {
return os << n.getFName() << " " << n.getMName() << " " << n.getSName();
}
Your constructor must assign the parameters you pass to the member variables, that doesn't happen automatically.
name (string fName, string mName, string sName) : fName(fName), mName(mName), sName(sName) {};
For your constructor, you have the three strings as your parameters but you aren't setting the member variables to their values. You can use an initializer list on the constructor like this...
name (string f, string m, string s)
: fName(f), mName(m), sName(s) // member(parameter) format
{
}
...or you can implement the setter stubs you have...
void setFName(string name) { this->fName = name;}
... and use them inside of your constructor like...
name (string fName, string mName, string sName) {
setFName(fName);
//...
}
Basically the parameters passed in the constructor are getting lost since you are not assigning it to the class vars..
Do something like:
name (string f, string m, string s) : fName(f), mName(m), sName(s){....};
try this. You forgot to implement Constructor of the class
#include <iostream>
#include <string.h>
using namespace std;
class name
{
string sFName, sMName, sSName;
public:
name (string FName, string MName, string SName);
void Display();
void setFName (string fName);
void setMName (string mName);
void setSName (string sName);
string getFName() const {return sFName;}
string getSName() const {return sSName;}
string getMName() const {return sMName;}
};
name::name(string FName, string MName, string SName )
{
sFName = FName;
sMName = MName;
sSName = SName;
}
void name::setFName(string fName)
{
sFName = fName;
}
void name::setMName(string mName)
{
sMName = mName;
}
void name::setSName(string sName)
{
sSName = sName;
}
void name::Display()
{
cout<< sFName<< endl;
cout<< sMName<< endl;
cout<< sSName<< endl;
}
int main ()
{
name myName ("Gianna", "Maria", "M");
myName.Display();
return 0;
}

Most elegant and less error prone way to check ctor parameters

Given the following simple constructor declaration of a person class:
Person(const string& _firstName, const string& _lastName, const string& _id);
What way is considered elegant and not error prone to make sure the given parameters are valid?
Say I want to make sure that an object of a type PERSON will contain empty strings even if only ONE of the given arguments is invalid.
I came up with this solution:
Person::Person(const string& _firstName, const string& _lastName, const string& _id) {
if (!isValidName(_firstName) || !isValidName(_lastName)) {
firstName = ""; lastName = ""; id = "";
throw InvalidNameException();
}
if (!isValidID(_id)) {
firstName = ""; lastName = ""; id = "";
throw InvalidIDException();
}
firstName = _firstName;
lastName = _lastName;
id = _id;
}
The ctor is now way too bloaty to my taste, I thought about writing an init method but I don't really like that solution.
Would love to hear some suggestions.
I would suggest initializing your member variables in the initializer list and then checking whether they're valid. If they're not, throw an exception.
Person::Person(const string& _firstName, const string& _lastName, const string& _id) :
firstName( _firstName ),
lastName( _lastName ),
id( _id )
{
if (!isValidName( firstName ) || !isValidName( lastName ) || !isValidID( id ) ) {
throw InvalidNameException();
}
Your member variables are initialized before you get into the constructor body. The code in the question would initialize the member variables as empty and then initialize them again when they're assigned to.
By throwing an exception, the object is not considered to be constructed anyway, so you don't need to "clear" member variables. Any member variable that is successfully constructed before your exception is thrown will have its destructor called. Note, that by throwing if your object throws an exception, it will not have its destructor called (because it was never fully created).
Why not wrap the isValidName and isValidId functions in
functions which either throws or returns the string:
std::string
checkedName( std::string const& name )
{
if ( !isValidName( name ) ) {
throw InvalidNameException();
}
return name;
}
std::string
checkedId( std::string const& id )
{
if ( !isValidID( id ) ) {
throw InvalidIDException();
}
return id;
}
and then:
Person::Person( std::string const& firstName,
std::string const& lastName,
std::string const& id )
: myFirstName( checkedName( firstName ) )
, myLastName( checkedName( lastName ) )
, myId( checkedId( id ) )
{
}
Alternatively (but less readable in my opinion), you can use the
ternary operator:
Person::Person( std::string const& firstName,
std::string const& lastName,
std::string const& id )
: myFirstName( isValidName( firstName )
? firstName
: throw InvalidNameException() )
, myLastName( isValidName( lastName )
? lastName
: throw InvalidNameException() )
, myId( isValidID( id )
? id
: throw InvalidIDException() )
{
}
Either way, you don't enter into the body of the constructor
unless the strings are valid.
That's hardly bloated. It's only a few lines. But it's always problematic to perform error checking in the constructor.
The best approach is probably to throw an exception just as you have, and have the caller decide how to handle errors.
And I really can't imagine why you must set _firstName and _lastName to empty strings after you've determined the arguments are invalid.
Person::Person(const string& _firstName, const string& _lastName, const string& _id) {
if (!isValidName(_firstName) || !isValidName(_lastName))
throw InvalidNameException();
if (!isValidID(_id))
throw InvalidIDException();
firstName = _firstName;
lastName = _lastName;
id = _id;
}
That's not bloated at all.
If you throw from a constructor, your object is considered to never have been constructed. There is no point setting the values to empty strings in that case as it would be undefined behavior anyway to somehow try to access the members after throwing an exception from the constructor.
Person::Person(const string& _firstName, const string& _lastName, const string& _id)
: firstName(_firstName), lastName(_lastName), id(_id) {
if (!isValidName(firstName) || !isValidName(lastName)) throw InvalidNameException();
if (!isValidID(_id)) throw InvalidIDException();
}
I think you need to separate your concerns.
Does it make sense to have a first_name without a last_name?
Does it make sense to have a first_name and a last_name without an id?
Does it make sense to have an invalid first_name, last_name, or id?
I believe the answer to all questions is "no". For that reason, I believe that the three entities belong together within an abstract concept called Identifier (or similar). This is the case because the checks and guarantees you need to offer are non-trivial.
The class could look as follows:
class Identifier {
public:
static void ValidateName(const std::string& name) {
if(name.size() <= 0) {
std::stringstream ss;
ss<<"Invalid name: "<<name<<" (expected non-empty string)";
throw std::invalid_argument(ss.str());
}
}
static void ValidateId(const std::string& id) {
if(id.size() != 10) {
std::stringstream ss;
ss<<"Invalid id: "<<id<<" (expected string of length 10)";
throw std::invalid_argument(ss.str());
}
}
Identifier(const std::string& first, const std::string& last, const std::string& id)
: m_first(first),
m_last(last),
m_id(id) {
Identifier::ValidateName(m_first);
Identifier::ValidateName(m_last);
Identifier::ValidateId(m_id);
}
const std::string& first_name() const {
return m_first;
}
const std::string& last_name() const {
return m_last;
}
const std::string& id() const {
return m_id;
}
private:
std::string m_first;
std::string m_last;
std::string m_id;
};
Given the way the class has been designed, it is impossible to create an invalid Identifier: one either passes all the tests, or the Identifier is never created in the first place.
In addition, notice that there is no way to invalidate an Identifier once it has been created; this guarantees that if an instance of Identifier exists, it will be valid for its entire existence.
Given that guarantee, you can now create your Person instance via a constructor which takes an Identifier; the constructor will never throw, and it does not need to make any checks. The Person class could look as follows:
class Person {
public:
Person(const Identifier& identifier) noexcept(true)
: m_identifier(identifier) { }
const std::string& first_name() const {
return m_identifier.first_name();
}
const std::string& last_name() const {
return m_identifier.last_name();
}
const std::string& id() const {
return m_identifier.id();
}
private:
Identifier m_identifier;
};
By separating your concerns in this manner:
You can augment the Identifier class with further checks or fields without ever touching the Person class: your classes can evolve independently
You can use Identifiers in other places without having to repeat the checks. For example: you could create Identifiers and introduce them into a database.
The final code is:
#include<iostream>
#include<sstream>
#include<stdexcept>
class Identifier {
public:
static void ValidateName(const std::string& name) {
if(name.size() <= 0) {
std::stringstream ss;
ss<<"Invalid name: "<<name<<" (expected non-empty string)";
throw std::invalid_argument(ss.str());
}
}
static void ValidateId(const std::string& id) {
if(id.size() != 10) {
std::stringstream ss;
ss<<"Invalid id: "<<id<<" (expected string of length 10)";
throw std::invalid_argument(ss.str());
}
}
Identifier(const std::string& first, const std::string& last, const std::string& id)
: m_first(first),
m_last(last),
m_id(id) {
Identifier::ValidateName(m_first);
Identifier::ValidateName(m_last);
Identifier::ValidateId(m_id);
}
const std::string& first_name() const {
return m_first;
}
const std::string& last_name() const {
return m_last;
}
const std::string& id() const {
return m_id;
}
private:
std::string m_first;
std::string m_last;
std::string m_id;
};
class Person {
public:
Person(const Identifier& identifier) noexcept(true)
: m_identifier(identifier) { }
const std::string& first_name() const {
return m_identifier.first_name();
}
const std::string& last_name() const {
return m_identifier.last_name();
}
const std::string& id() const {
return m_identifier.id();
}
private:
Identifier m_identifier;
};
int main() {
Identifier id("John", "Doe", "1234567890");
Person p(id); // cannot throw because id has already been
// constructed
std::cout<<p.last_name()<<", "<<p.first_name()<<" Id: "<<p.id()<<std::endl;
try {
Identifier id2("Sue", "Smith", "126789");
Person p2(id2);
std::cout<<p2.first_name()<<std::endl;
} catch(const std::exception &e) {
std::cout<<e.what()<<std::endl;
}
try {
Identifier id3("", "Smith", "126789");
Person p3(id3);
std::cout<<p3.first_name()<<std::endl;
} catch(const std::exception &e) {
std::cout<<e.what()<<std::endl;
}
return 0;
}
which can be compiled using the following command (GCC 4.8.1 on OS X 10.7.4)
g++ validated_names.cpp -std=c++11 -Wall -Wextra
and produce the following output:
./a.out
Doe, John Id: 1234567890
Invalid id: 126789 (expected string of length 10)
Invalid name: (expected non-empty string)

access a member of class using vector

I have a class defined as
typedef std::string Name;
typedef int Age;
typedef std::string Level;
class Employee
{
public:
// Employee (arguments);
// virtual ~Employee ();
void name(Name const & name) { name_ = name; }
Name name() const { return name_; }
void age(Age const & age) { age_ = age; }
Age age() const { return age_; }
void level(Level const & level) { level_ = level; }
Level level() const { return level_; }
private:
Name name_;
Age age_;
Level level_;
};
std::vector<Employee> read_file(std::string filename);
std::vector<Employee> employees = read_file("data.txt");
std::cout << employees.size() << std:: endl;
for(std::vector<Employee>::iterator it = employees.begin(); it != employees.end(); ++it)
{
std::cout << *it << std::endl;
}
Is there a way for me to access the members of the class Employee using this vector defined above? I want to construct a map container with level of the employee as the key value.
If you want to access members of Employee from the iterator you can use the member access operator ->:
the_map[it->level()] = blah;
Unless I'm misinterpreting your question, this is simple enough.
it is an iterator over the vector of Employee.
*it is the Employee
it-> lets you access members of that Employee
e.g.: it->name()
So, if you want to build a map of employee level to Employee, you can do this:
std::map<Level, Employee> employeeMap;
for(std::vector<Employee>::iterator it = employees.begin();
it != employees.end();
++it)
{
employeeMap[ it->level() ] = *it;
}
Now you have your employeeMap, which maps the employee's Level to the Employee
const Name name = it->name();
const Age age = it->age();
const Level level = it->level();
or
const Name name = employees[i].name();
const Age age = employees[i].age();
const Level level = employees[i].level();
will work fine.
I would, however, strongly recommend you return each of the above items as references as it will generally be a lot faster than making a copy of the object.
ie
class Employee
{
public:
// Employee (arguments);
// virtual ~Employee ();
void name(Name const & name) { name_ = name; }
Name& name() { return name_; }
const Name& name() const { return name_; }
void age(Age const & age) { age_ = age; }
Age& age() { return age_; }
const Age& age() const { return age_; }
void level(Level const & level) { level_ = level; }
Level& level() { return level_; }
const Level& level() const { return level_; }
private:
Name name_;
Age age_;
Level level_;
};
Then you can access the values by reference as follows:
const Name& name = it->name();
const Age& age = it->age();
const Level& level = it->level();
It also means you can change the values like this:
it->name() = "Goz";
it->age() = 33;
it->level() = "Programmer";