Chapter 2: Object-Oriented Design
2.1 Goals and Principles
2.1.1 Object-Oriented Design Goals
  -  Robustness: capable of
handling unexpected inputs
that are not explicitly defined for its application
-  Adaptability: software
needs to evolve over time in
response to changing conditions in its environment
-  Reusability: code
should
reusable as a component of different systems in various applications
2.1.2 Object-Oriented Design Principles
  - 
Abstraction: to distill
the complicated system down to its most fundamental parts and describe
these parts in a simple, precise language
- 
Encapsulation:different
components of a software system should not reveal the internal details
of their respective implementation
- 
Modularity: refers to an
organizing structure in which different components of a software system
are divided into separate functional units
2.2 Inheritance and Polymorphism
2.2.1 Inheritance in C++
Inheritance allows the design of generic classes that can be
specialized to more particular classes, with the specialized classes
reusing the code from the generic class.
  class Person {       // base class  
private:
   string name;      // name
   string ssn;       // social security number
public: 
   //...
   void print();     // print data
   string getName(); // retrieve name
}; 
class Student : public Person {     // derived class
private:
   string major;    // major subject
   int gradYear;    // graduate year
public:
   //...
   void print();                      // print data
   void changeMajor(string newMajor); // change major
 };
Member Functions
  Person person(...);       // define a person 
Student student(...);     // define a student
cout << student.getName();// invokes Person::getName()
person.print();           // invokes Person::print();
student.print();          // invokes Student::print();
person.changeMajor("Math"); // ERROR!
student.changeMajor("Math"); // OK
void Person::print()    // definition of Person print
{ cout << name << " " << ssn; }
void Student::print()   // definition of Student print
{ Person::print();      // first print Person data
  cout << major << gradYear;
} 
Illustrating Class Protection
  class Base {
   private:
       int priv;
   protected:
       int prot;
   public:
       int publ;
};
class Derived: public Base { 
   void someMemberFunction() 
   { cout << priv;    // ERROR: private member
     cout << prot;    // OK
     cout << publ;    // OK
   }
};
class Unrelated {
  Base X;
  void anotherMemberFunction() 
  {  cout << X.priv;   // ERROR: private member
     cout << X.prot;   // ERROR: protected member
     cout << X.publ;   // OK
  }
};
Constructors and Destructors
  Person::Person(const string &nm, const string &ss)  
: name(nm), ssn(ss) {}           // initializer list
Student::Student(const string &nm, const string &ss,
                 const string &maj, int year)
: Person(nm, ss),      // initialize Person data members
  major(maj),          // initialize member
  gradYear(year) {}    // initialize gradYear
Person::~Person()      // Person destructor
{ ... }
Student::~Student()    // Student destructor
{ ... }
Student* s = new Student(...);
//...
delete s;   // calls ~Student() then ~Person()
Static Binding
  Person* pp[100];  
pp[0] = new Person(...); 
pp[1] = new Student(...);
cout << pp[1]->getName();   // OK
pp[0]->print();             // calls Person::print()
pp[1]->print();             // calls Person::print()
pp[1]->changeMajor(...);    // ERROR!
Dynamic Binding and Virtual
Functions
  class Person {       // base class  
   virtual void print();         // print data
   //...
}; 
class Student : public Person {  // derived class
   virtual void print();         // print data
   //...
 };
Person* pp[100];  
pp[0] = new Person(...); 
pp[1] = new Student(...);
pp[0]->print();             // calls Person::print()
pp[1]->print();             // calls Student::print()
pp[1]->changeMajor(...);    // OK
Virtual
Destructors
If a class defines any virtual
functions, it should define a
virtual destructor, even if it is empty.
  delete [] pp;
2.2.2 Polymorphism
The ability of a variable to take different types!
2.3 Templates
2.3.1 Function Templates
  - Minimum of two integers:
 
      int min(int a, int b)  
 { return (a < b ? a : b); }
 
 
 
- Minimum of doubles:
 
      double min(double a, double b)  
 { return (a < b ? a : b); }
 
 
 
- Generic function for an arbitrary type T, called function template:
 
      template<typename T>      // parameter list
 T min(T a, T b)           // returns the minimum of a and b
 { return (a < b ? a : b); }
 
 
 
- We can invoke our templated function to compute the minimum of
objects
of many different types. We could use any type, provided that the less
than operator (<) is
defined for this type. The
compiler looks at the argument types,
and determine which form of the function to instantiate:
 
      cout << min(3, 4);      // invokes min<int>(3,4)
 cout << min(6.9, 3.5);  // invokes min<double>(6.9, 3.5)
 cout << min('t', 'g');  // invokes min<char>('t', 'g')
 
 
 
2.3.2 Class Templates
  template <typename Object>
class BasicVector {
   Object* a;                  // array storing an element
   int capacity;               // length of array a
public:
   BasicVector(int cap = 10)   // constructor
   {  capacity = cap;
      a = new Object[capacity];// allocate array storage
   }
   Object& elemAtRank(int r)   // access element at index r
   {  return a[r];  }
// ...
};
  BasicVector<int> iv(5);     // vector of 5 integers
BasicVector<double> dv(20); // vector of 20 doubles
BasicVector<string> sv(10); // vector of 10 strings
//...
iv.elemAtRank(3) = 8;       // iv[3] = 8;
dv.elemAtRank(14) = 2.5;    // dv[14] = 2.5
sv.elemAtRank(7) = "hello"; // sv[7] = "hello"
2.4 Exceptions
Exceptions are unexpected events that occur during the execution of a
program.
2.4.1 Exception Objects
Using Inheritance to Define New
Exception Types
  class MathException {  // generic math exception
private:
  string errMsg;       // error message
public:
  MathException(const string& err) { errMsg = err; }
};
class ZeroDivisionException : public MathException {
public:
  ZeroDivisionException(const string& err) 
: MathException(err) {}
};
class NegativeRootException : public MathException {
public:
  NegativeRootException(const string& err) 
: MathException(err) {}
};
2.4.2 Throwing and Catching
Exceptions
  try {
// ...
if (divisor == 0) throw ZeroDivisionException("Division by zero");
//...
}
catch (ZeroDivisionException& zde) 
{ // handle division by zero
}
catch (MathException& me) 
{ // handle any math exception other than division by zero
}
Once execution of the catch block completes, control flow continues
with the first statement after the last catch block.
2.4.3 Exception Specification
  void calculator() throw(ZeroDivisionException, NegativeRootException)
{
  //... 
}
void funct1();         // can throw any exception
void funct2() throw(); // can throw no exception
Generic Exception Class
  class RuntimeException {  // generic run-time exception
private:
  string errorMsg;
public:
  RuntimeException(const string& err) { errorMsg = err; }
  string getMessage() const { return errorMsg; }
};
inline std::ostream& operator<<(std::ostream& out, const RuntimeException& e)
  { return out << e.getMessage(); }