Section 6 - Operators and Inheritance
5A.6.1 Constructor Chaining and Initialization
Before we see the complete example, let me give you some common notation. When we have a constructor that takes parameters, there is a short-hand for using those parameters to initialize data. Instead of this:
// Course method definitions -------------------------- Course::Course(string instr, string ttl ) { instructor = instr; title = ttl; }
We can do this:
// Course method definitions -------------------------- Course::Course(string instr, string ttl ) : instructor(instr), title(ttl) { // nothing needed inside }
Now there is one important caveat here: this kind of initialization affords no protection since no filtering is going on. We are just setting the private data to the passed values without examining those values. But if that works in your situation, you can use this syntax.
There is a more useful version of this concept, and that is constructor chaining: calling a base class constructor from a derived class constructor. As you know, when we instantiate a derived class object, we may want to set some of the base class data. Since that data may not be directly accessible to us, we pass values to the base class constructor. It is done in a manner similar to the above initialization, as follows (Assume CSCourse is derived from Course). Then the definition of its constructor might look like this:
CSCourse::CSCourse(string instr, string title, string lab ) : Course(instr, title) { computerLab = lab; }
So we are passing some of the parameters up to the base class constructor (instr and title) and using one of the parameters, lab, to set our derived data, computerLab.
We can even combine the two concepts above:
CSCourse::CSCourse(string instr, string title, string lab ) : Course(instr, title), computerLab(lab) { // nothing left to do }
5A.6.2 Full Example
With that, we can look at an example of all the recent topics:
#include <iostream> #include <string> using namespace std; // Course prototype -------------------------------- class Course { friend ostream &operator<<(ostream &ostrm, const Course &crs); protected: string instructor; string title; public: Course( string instr = "undefined", string title = "undefined" ); Course ( const Course &crs ); Course& operator=(const Course &crs); virtual ~Course() {} string getInstructor() { return instructor; } string getTitle() { return title; } static const int MIN_STRING_LEN = 3; static const int MAX_STRING_LEN = 50; }; class CSCourse : public Course { friend ostream &operator<<(ostream &ostrm, const CSCourse &crs); private: string computerLab; public: CSCourse(string instr = "loceff", string title = "undefined", string computerLab = "room 522"); CSCourse& operator=(const Course &crs); CSCourse& operator=(const CSCourse &crs); virtual ~CSCourse() {} }; // main method --------------------------------------- int main() { Course phy27a("Harmon", "Physics"); CSCourse cs2a("loceff", "C++", "Room L-54"); cout << phy27a; cout << cs2a; cs2a = phy27a; cout << cs2a; return 0; } // Course method definitions -------------------------- Course::Course(string instr, string ttl ) { // a more complete application would use mutators if (instr.length() >= MIN_STRING_LEN && instr.length() <= MAX_STRING_LEN) instructor = instr; else instructor = "(no instructor)"; if (ttl.length() >= MIN_STRING_LEN && ttl.length() <= MAX_STRING_LEN) title = ttl; else title = "(no title)"; } Course::Course( const Course &crs) { *this = crs; // copy all simple data } Course& Course::operator=( const Course &crs) { if (this != &crs) { this->instructor = crs.instructor; this->title = crs.title; } return *this; } // CSCourse method definitions -------------------------- CSCourse::CSCourse(string instr, string title, string lab ) : Course(instr, title), computerLab(lab) { // nothing left to do } CSCourse& CSCourse::operator=(const Course &crs) { if (this != &crs) { Course::operator=(crs); this->computerLab = "undefined"; } return *this; } CSCourse& CSCourse::operator=(const CSCourse &crs) { if (this != &crs) { Course::operator=(crs); this->computerLab = crs.computerLab; } return *this; } // end Course method definitions --------------------- // overloaded operator functions --------------------- ostream &operator<<(ostream &ostrm, const Course &crs) { ostrm << "\n--------------------------------\n"; ostrm << "Class Title: " << crs.title << " " << "Instructor: " << crs.instructor << endl; cout << endl; return ostrm; } // overloaded operator functions --------------------- ostream &operator<<(ostream &ostrm, const CSCourse &crs) { ostrm << (Course)crs; cout << crs.computerLab << endl << endl; return ostrm; }
Here is the output:
