6.1. Simple Derivation

[ fromfile: inheritance-intro.xml id: derivation1 ]

[Tip] What's Wrong with Repeated Code?

Refactoring is a process of improving the design of software, without changing its underlying behavior. One step of refactoring involves replacing blocks of similar code with calls to reusable functions.

Figure 6.1.  UML Diagram of Inheritance

UML Diagram of Inheritance

Example 6.1. src/derivation/qmono/student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <QString>

class Student  {
 public:
    Student(QString nm, long id, QString major, int year = 1);
    ~Student() {}
    QString getClassName() const; 
    QString toString() const;
 private:
    QString m_Name;
    QString m_Major;
    long m_StudentId;
 protected:
    int m_Year;
    QString yearStr() const;
};

class Undergrad: public Student {
 public:
    Undergrad(QString name, long id, QString major, int year, int sat);
    QString getClassName() const;
    QString toString() const;
 private:
    int m_SAT;  1

};

class GradStudent : public Student {
 public:
    enum Support { ta, ra, fellowship, other };
    GradStudent(QString nm, long id, QString major,
                int yr, Support support);

    QString getClassName() const ;
    QString toString() const;
 protected:
    static QString supportStr(Support sup) ;
 private:
    Support  m_Support;
};

#endif        //  #ifndef STUDENT_H

1

Scholastic Aptitude Test score total.


Example 6.2. src/derivation/qmono/student.cpp

[ . . . . ]

#include <QTextStream>
#include "student.h"

Student::Student(QString nm, long id, QString major, int year)
        : m_Name(nm), m_Major(major), m_StudentId(id), m_Year(year) {}


QString Student::getClassName() const {
    return "Student";
}

QString Student::toString() const {
    QString retval;
    QTextStream os(&retval);                1
    os << "[" << getClassName() << "]" 
         << " name: " << m_Name
         << "; Id: " << m_StudentId
         << "; Year: " << yearStr()
         << "; \nMajor: " << m_Major  ;
    return retval;
}

1

Write to the stream and return its string.


Example 6.3. src/derivation/qmono/student.cpp

[ . . . . ]

Undergrad::Undergrad(QString name, long id, QString major, 
      int year, int sat)
: Student(name, id, major, year), m_SAT(sat)  1
   { }

QString Undergrad::getClassName() const {
    return "Undergrad";
}

QString Undergrad::toString() const {
    QString result;
    QTextStream os(&result);
    os <<  Student::toString()                2
       << "  [SAT: "                          3
       << m_SAT
       << " ]\n";
    return result;
}

1

The base class object is treated as a subobject of the derived object. Class members and base classes both must be initialized in an order determined by the order that they appear in the class definition.

2

Call the base class version.

3

Add items that are specific to Undergrad.


Member Initialization for Base Classes

Example 6.4. src/derivation/qmono/student.cpp

[ . . . . ]

GradStudent::
GradStudent(QString nm, long id, QString major, int yr, 
                   Support support) :Student(nm, id, major, yr), 
            m_Support(support) { }

QString GradStudent::toString() const {       1
   return QString("%1%2%3 ]\n")
       .arg(Student::toString())              2
       .arg("  [Support: ")                   3 
       .arg(supportStr(m_Support));
}

1

Another QString style.

2

Call the base class version

3

Then add items that are specific to GradStudent.


Extending.  Inside both derived class versions of toString(), before the derived class attributes are handled, we explicitly call Student::toString(), which handles the (private) base class attributes. Each derived class version of toString() extends the functionality of Student::toString().