// variations on the person and student class to demonstrate the use of // pointers to avoid the slicing problem and the need to define a virtual // destructor in the base class to avoid memory leaks. #include #include #include #include using namespace std; // base class for inheritance class person { public: person(const string & s, const string & n) : ssn(s), name(n) { // nothing else to do } person(const person & rhs) : ssn(rhs.ssn), name(rhs.name) { // nothing else to do } person & operator=(const person & rhs) { if (this != &rhs) { ssn = rhs.ssn; name = rhs.name; } return *this; } virtual ~person() { // nothing to do } const string get_name() const { return name; } // had to declare this function to be virtual to get polymorphic behavior virtual string to_string() const { ostringstream out; out << ssn << ", " << name; return out.str(); } private: string ssn; string name; }; // this is a subclass of person that adds a gpa instance variable class student: public person { public: student(const string & s, const string & n, double g) : person(s, n), gpa(g), dashes(person::to_string().size(), '-') { // nothing else to do } student(const student & rhs) : person(rhs), gpa(rhs.gpa), dashes(rhs.dashes) { // nothing else to do } student & operator=(const student & rhs) { if (this != &rhs) { person::operator=(rhs); gpa = rhs.gpa; dashes = rhs.dashes; } return *this; } string to_string() const { ostringstream out; out << person::to_string() << endl << dashes << endl << gpa; return out.str(); } private: double gpa; string dashes; }; int main() { person p1("374-23-4879", "Joe Smith"); student s1("732-33-2783", "Sarah Gordon", 3.95); cout << p1.to_string() << endl; cout << s1.to_string() << endl; cout << endl; // polymorphism person & p2 = s1; cout << p2.to_string() << endl; cout << endl; // example of "slicing" (a BIG problem) vector v; v.push_back(p1); v.push_back(s1); for (const person & p : v) { cout << p.to_string() << endl; } cout << endl; // this version works because of the pointers vector v2; v2.push_back(&p1); v2.push_back(&s1); for (const person * p : v2) { cout << p->to_string() << endl; } cout << endl; // this caused a problem without a virtual destructor person * s2 = new student("999-99-9999", "Real Donald Trump", 3.0); cout << s2->to_string() << endl; delete s2; cout << endl; // testing copy constructor and assignment operator for person person p3(p1); cout << p3.to_string() << endl; person p4("234-33-2838", "Jill Biden"); p3 = p4; cout << p3.to_string() << endl; cout << p4.to_string() << endl; cout << endl; // testing copy constructor and assignment operator for student student s3(s1); cout << s3.to_string() << endl; student s4("234-11-9834", "Joe Biden", 3.99); s3 = s4; cout << s3.to_string() << endl; cout << s4.to_string() << endl; return 0; }