Polymorphism vector in C++ - c++

I am trying to do a polymorphism in C++ language. My parent class is Person then there is a derived class called Student. Here is my Person.h and .cpp:
class Person
{
public:
Person(string name);
virtual void display() const;
string get_name() const;
void set_name(string name);
string get_birthDay() const;
void set_birthDay(string birthDay);
private:
string name;
string birthDay;
};
.cpp:
Person::Person(string name)
{
this->name = name;
}
string Person::get_name() const
{
return name;
}
void Person::set_name(string name)
{
this->name = name;
}
string Person::get_birthDay() const
{
return birthDay;
}
void Person::set_birthDay(string birthDay)
{
this->birthDay = birthDay;
}
void Person::display() const
{
cout << get_name() << " " << get_birthDay() << endl;
}
And this is my Student.h and .cpp:
class Student : public Person
{
public:
Student(string name, string major);
virtual void display() const;
string get_major() const;
void set_major(string major);
private:
string major;
};
.cpp:
Student::Student(string name, string major)
:Person(name)
{
this->major = major;
}
string Student::get_major() const
{
return major;
}
void Student::set_major(string major)
{
this->major = major;
}
void Student::display() const
{
cout << get_name() << " " << get_major() << endl;
}
All working perfectly until my main method. Here is my main method:
int main()
{
vector <Person*> person_list;
person_list.push_back(Student("Student","IT"));
person_list.push_back(Instructor("Instrructor", 2500));
for(int count=0; count< person_list.size(); count++)
{
cout << person_list[count]->display() << endl;
}
system("Pause");
return 0;
}
I got an error at the push_back and cout there. The error message for push_back to vector is: no instance of overloaded function matches the argument list. As for the cout, no operator matches the operands. I have no idea why. Anybody can help me fix it?
Thanks in advance.

Your person_list stores pointer but you pushed object instead:
To fix your issue:
person_list.push_back(new Student("Student","IT"));
//^^^^
person_list.push_back(new Instructor("Instrructor", 2500));
To store pointer in STL container, better use smart pointer:
#include <memory>
std::vector <std::unique_ptr<Person>> person_list;

You will need to push back a pointer to Student; i.e. use
person_list.push_back(new Student("Student","IT")); etc.
But, you will need to be very very careful with memory, since you will need to delete the memory you've allocated; the vector will not do this for you when it destructs.
Consider using a smart pointer instead.

cout << person_list[count]->display() << endl;
The display() function is of void return type. You cannot output that.
As for the push_back: like the others said, if you've got a vector of pointers, you need to push_back a pointer, not the object.

Related

Pointer to object and destructor

I am trying to understand why my code doesn't use destructor of class Name. In fact I write two classes. First one called Name and a second called Person that have a pointer to object Name. What I don't understand is why the program doesn't called to the destructor of Name, because I think when I write "new" I create a new object so it has to call to the destructor of class Name before closing program.
Can you explain what wrong in my understanding. Thanks !
class Name
{
private:
string name;
public:
Name(string name) : name(name) { cout << "Hello " << name << endl; }
~Name() { cout << "See you soon " << name; }
};
class Person
{
private:
Name* myname;
public:
Person(string name) { myname = new Name(name); }
~Person() { cout << "Exit" << endl; }
};
int main()
{
Person("Marc");
Person("Alex");
}
You are creating a memory leak here, because you create a new instance of Name here
Person(string name) { myname = new Name(name); }
but you never delete it. This is the reason why the destrcutor of Name is never called.
To avoid this you can use an std::unique_ptr or an std::shared_ptr, which will automatically handle the lifetime of such an object.
std::unique_ptr<Name> myname;
Person(string name) { myname = std::make_unique<Name>(name); }
An alternative is to delete the object in your destructor, but in C++ you should avoid direct handling of dynamic raw pointers.
#include <iostream>
#include <memory>
class Name
{
private:
std::string name;
public:
Name(std::string name) : name(name) { std::cout << "Hello " << name << std::endl; }
~Name() { std::cout << "See you soon " << name << std::endl; }
};
class Person
{
private:
std::unique_ptr<Name> myname;
public:
Person(std::string name) { myname = std::make_unique<Name>(name); }
~Person() { std::cout << "Exit" << std::endl; }
};
int main(int argc, char **argv)
{
Person("Marc");
Person("Alex");
return 0;
}
As myname object in Person's class is a pointer. For every pointer there must be a delete statement to deallocate the memory.
Replace Person's class Destructor as:
~Person() {
cout << "Exit" << endl;
delete myname;
}

C++ Keep on getting an expression must have a class type?

I have a Person class which has a vector of Accounts. The account class is an abstract class and has a class type CurrentAccount. I have a method which will print out a Person account details called 'printAllAccounts'. But I see to be getting an error where it says 'accounts' and it says 'expression must have a class type'.
Here is the person header class:
Person.h
#include "pch.h"
#include "Account.h"
using namespace std;
class Person {
public:
Person(string);
void addAccount(Account &);
bool closeAccount(int *);
void printAllAccounts();
bool creditMoney(int *, double *);
bool debitMoney(int *, double *);
virtual ~Person();
private:
const string name;
vector<Account> accounts;
};
Here is the method for for Person.cpp:
void Person::printAllAccounts()
{
if (accounts.size() > 0) {
for (int i = 0; i < accounts.size(); i++)
{
//below line of accounts is where error is happening
cout << **accounts**.at(i).printDetails().c_str() << endl;
}
}
else {
cout << "Person : " << name << " has no accounts" << endl;
}
}
[Edit]
Here is print details in the Account Class:
Actually there is an error on return toRet;
Account.cpp file
void Account::printDetails() const
{
ostringstream conAcc, conBal;
conAcc << this->accountNo;
string toRet;
toRet += "Account No: ";
toRet += conAcc.str();
toRet += " Balance : ";
conBal << this->balance;
toRet += conBal.str();
return toRet;
}
Here is the Account.h header file(abstract class)
#include "pch.h"
using namespace std;
class Account {
public:
Account(int *, double *);
virtual ~Account();
bool debit(double *);
bool credit(double *);
int getAccNo();
//making it abstract
virtual double getBalance() const = 0;
virtual void printDetails() const;
private:
double balance;
int accountNo;
};
std::vector<Account> will internally create an array of Account and thus cannot store derived classes like CurrentAccount. Even if you add a CurrentAccount object, the vector will create a copy of type Account and store that. And if Account is abstract, you won't be able to store anything at all, since an abstract class cannot be instantiated. (You might want to look up object slicing to read more about what's going on.)
To fix this, you can use std::vector<std::unique_ptr<Account>>. That way your vector holds pointers of type Account*, which can point to derived classes like CurrentAccount.

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++ newbie: Operation of make_shared

I am new to C++. Can someone please let me know what is wrong with the following code segment -
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
std::map<std::string, std::shared_ptr<Person>> plist;
std::string namestr = "Hoo";
std::shared_ptr<Person> r1(std::make_shared<Person>("Dull"));
plist.insert({"Key1", r1});
auto u = plist.find("Key1");
shared_ptr<Person> v = u->second;
v->dump();
plist.erase(plist.find("Key1"));
My intention is to create a database of Person objects and I was trying to use shared_ptr for that.
v->dump() causes a segmentation fault. However, if I use the 'namestr' variable instead of the string literal "Dull" then the v->dump() appears to work correctly, i.e. the following -
std::shared_ptr<Person> r1(std::make_shared<Person>(namestr));
Also, the following way also seems to work even though I use a string literal in the intializer.
std::shared_ptr<Person> r1(new Person("Dull"));
Pointers to the mistake I am making would be much appreciated!
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
this is storing a reference to a string whose life time is not guaranteed. You should do
class Person {
public:
const std::string name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
You code fails because "Dull" created a temporary string that went out of scope immediately

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;
}