Reputation: 2052
I am trying to create a vector of Person objects. However I really want to store Adult, Professor, and Student objects which are derived from the Person base class. After asking this question I have learned that my issue was in Object Splicing and that it would save the derived classes as a Person class because that is what the vector is of. I have attempted to modify the code to rectify the situation however I still am coming across some errors and need some additional assistance. Thanks!
Here is my main.cpp code:
#include "Person.h"
#include "Professor.h"
#include "Student.h"
#include "Adult.h"
#include <vector>
#include <string>
#include <iostream>
using namespace std;
template<typename T> void addPerson(vector<Person *> &personVector) {
cout << "DEBUG" << endl;
personVector.push_back(new T());
}
void addFriend(vector<Person *> &personVector) {
bool loop = true;
while (loop) {
cout << "\nWhich Person would you like to create? " << endl;
cout << " 1. Professor" << endl;
cout << " 2. Student" << endl;
cout << " 3. Adult" << endl;
int caseVar;
cin >> caseVar;
switch (caseVar) {
case 1:
addPerson<Professor>(personVector);
// old incorrect line: addPerson<Professor *>(personVector);
loop = false;
break;
case 2:
addPerson<Student>(personVector);
// old incorrect line: addPerson<Student *>(personVector);
loop = false;
break;
case 3:
addPerson<Adult>(personVector);
// old incorrect line: addPerson<Adult *>(personVector);
loop = false;
break;
default: cout << "Unknown Entry Please Try Again." << endl;
}
}
}
void displayFriends(vector<Person *> &personVector) {
if (personVector.size() > 1) {
for (unsigned i = 0; personVector.size() > i; i++)
cout << i+1 << ". " << personVector[i]->getName() << endl;
cout << "DEBUG" << endl;
}
}
void viewFriend(vector<Person *> &personVector) {
if (personVector.size() > 1) {
displayFriends(personVector);
cout << "Which # friend would you like to view? ";
int num;
cin >> num;
personVector[num-1]->coutPerson();
} else if (personVector.size() == 1) {
personVector[0]->coutPerson();
} else {
cout << "No friends to View." << endl;
}
}
void deleteElementFromArray(int element, vector<Person *> &personVector) {
vector<Person *> newPersonVector;
for (unsigned i = 0; personVector.size() > i; i++)
if (i != element - 1)
newPersonVector.push_back(personVector[i]);
personVector = newPersonVector;
}
void removeFriend(vector<Person *> &personVector) {
if (personVector.size() > 1) {
displayFriends(personVector);
cout << "Which # friend would you like to remove? ";
unsigned num;
cin >> num;
if (num <= personVector.size())
deleteElementFromArray(num, personVector);
else
cout << "Invalid Selection" << endl;
} else if (personVector.size() == 1) {
cout << "Removed one and only friend" << endl;
} else {
cout << "No friends to Remove." << endl;
}
}
int main() {
vector<Person *> personVector;
// Run Main Menu
cout << "Friends with Stuff" << endl;
cout << "Adding 5 friends to the list" << endl;
personVector.push_back(new Person("James"));
personVector.push_back(new Person("Martin"));
personVector.push_back(new Person("Sammi"));
personVector.push_back(new Person("Donny"));
personVector.push_back(new Person("Ronald"));
bool loop = true;
while (loop) {
cout << "\nWhat would you like to do? " << endl;
cout << " 1. Add New Friend" << endl;
cout << " 2. View Friend" << endl;
cout << " 3. Remove Friend" << endl;
cout << " 4. Clear Friends" << endl;
cout << " 5. Get Object" << endl;
cout << " 6. Exit" << endl;
int caseVar;
cin >> caseVar;
switch (caseVar) {
case 1:
addFriend(personVector);
break;
case 2:
viewFriend(personVector);
break;
case 3:
removeFriend(personVector);
break;
case 4:
personVector.clear();
break;
case 5:
break;
case 6:
loop = false;
break;
default: cout << "Unknown Entry Please Try Again." << endl;
}
}
}
I am getting the following errors
InitializeBuildStatus:
1> Touching "Debug\FPVisualStudio.unsuccessfulbuild".
1>ClCompile:
1> main.cpp
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Professor **' to 'Person *&&'
1> with
1> [
1> _Ty=Person *
1> ]
1> Reason: cannot convert from 'Professor **' to 'Person *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1> \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(26) : see reference to function template instantiation 'void addPerson<Professor*>(std::vector<_Ty>)' being compiled
1> with
1> [
1> _Ty=Person *
1> ]
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Student **' to 'Person *&&'
1> with
1> [
1> _Ty=Person *
1> ]
1> Reason: cannot convert from 'Student **' to 'Person *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1> \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(30) : see reference to function template instantiation 'void addPerson<Student*>(std::vector<_Ty>)' being compiled
1> with
1> [
1> _Ty=Person *
1> ]
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Adult **' to 'Person *&&'
1> with
1> [
1> _Ty=Person *
1> ]
1> Reason: cannot convert from 'Adult **' to 'Person *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1> \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(34) : see reference to function template instantiation 'void addPerson<Adult*>(std::vector<_Ty>)' being compiled
1> with
1> [
1> _Ty=Person *
1> ]
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:02.90
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I believe that it is telling me that I have too many pointers in my code. However I don't understand why this would be the case. The only places I have pointers are saying that the vector contains which I need to repeat in each case. And these pointers are needed so I don't have object slicing.
Person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include "Date.h"
#include "PhoneNumber.h"
using namespace std;
class Person
{
protected:
string name;
Date birthday;
PhoneNumber phoneNumber;
string city, state;
public:
// Constructors
Person();
Person(string name) {
this->name = name;
birthday = Date();
phoneNumber = PhoneNumber("0000000000");
city = "Unknown";
state = "Unknown";
}
// Getter and Setter Methods
string getName();
void setName(string);
Date getBirthday();
// Methods
void coutPerson();
};
#endif
Person.cpp
#include "Person.h"
#include "PhoneNumber.h"
#include "Date.h"
#include <string>
#include <iostream>
using namespace std;
// Constructors
Person::Person() {
cin.ignore();
cout << "Name? ";
getline(cin, name);
cout << "Birthday: " << endl;
birthday.askUserForDate();
phoneNumber.create();
cout << "City? ";
getline(cin, city);
cout << "State? ";
getline(cin, state);
}
// Getter and Setter Methods
string Person::getName() {
return name;
}
void Person::setName(string name) {
this->name = name;
}
void Person::coutPerson() {
cout << name << endl;
birthday.coutDate();
phoneNumber.coutPhoneNumber();
cout << city << ", " << state << endl;
}
// Methods
Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include "Person.h"
using namespace std;
class Student : public Person
{
private:
string dorm;
int dormRoom;
public:
// Constructors
Student();
Student(Student &);
// Getter and Setter Methods
// Methods
void coutPerson();
};
#endif
Student.cpp
#include "Student.h"
#include "Person.h"
#include <string>
#include <iostream>
using namespace std;
// Constructors
Student::Student() {
cin.ignore();
cout << "Dorm? ";
getline(cin, dorm);
cout << "Dorm Room #? ";
cin >> dormRoom;
}
// TODO Copy Constructors
// TODO Deconstructors
// Overload < > ==
Student::Student(Student &student) {
Person::Person(student);
dorm = student.dorm;
dormRoom = student.dormRoom;
}
void Student::coutPerson() {
cout << "DEBUG: Student::coutPerson()" << endl;
Person::coutPerson();
cout << "Dorm Room: " << this->dorm << " " << this->dormRoom << endl;
}
// Methods
Upvotes: 2
Views: 2433
Reputation: 8583
You need to remove the *
in your template parameters.
For instance:
addPerson<Professor *>(personVector);
Replace by:
addPerson<Professor>(personVector);
Currently, you're making it create a Professor **
.
Update: and in your main()
, you should create the persons using new Person("Name")
, what you're using right now doesn't make sense, ie 'take the adress of this type' is working, but is a very bad idea (taking the address of an object created on the stack).
For instance:
personVector.push_back(&Person("James"));
Replace by:
personVector.push_back(new Person("James"));
Update2: please note that you're responsible for freeing the memory you're allocating that way at some point.
Upvotes: 2
Reputation: 88707
Your template parameters are pointers but shouldn't since in your methods, e.g. template<typename T> void addPerson(...)
you create a new instance of T
using new
and thus you create a new pointer to a person (i.e. new Person*()
which will result in a Person***
).
Thus, just call it like this: addPerson<Professor>(personVector);
which will transform new T()
into new Professor()
and thus yields a Professor*
result.
Another thing:
void deleteElementFromArray(int element, vector<Person *> personVector) {
vector<Person *> newPersonVector;
for (unsigned i = 0; personVector.size() > i; i++)
if (i != element - 1)
newPersonVector.push_back(personVector[i]);
personVector = newPersonVector;
}
First, you're removing element - 1
so be aware that you can't pass 0 (i.e. element
is a one-based index here).
Second, you assign newPersonVector
to the parameter personVector
. However, since you're passing the vector by value (it is copied) that change won't be visible outside that function.
You have several solutions to this:
personVector
rather than copying those that should not be deleted. Use something like personVector.erase(personVector.begin() + element)
for that (note that the syntax here might not be quite right, but you should get it).void deleteElementFromArray(int element, vector<Person *>* personVector)
personVector = removeFriend(personVector);
I'd personally prefer option 1 since it reuses the vector and thus reduces copy operations.
Upvotes: 2
Reputation: 105
the code
addPerson<Professor *>(personVector);
try to modify as:
addPerson<Professor>(personVector);
Upvotes: 1