Classes
=======



In C++ a class splits into two sepatrate parts:

 - interface, placed in a header file: x.h
 - implementation, placed in a source: x.cpp
          and compiled separatedly to: x.o (x.a or x.so)

Users of the class includes the header file (x.h), and should
link the object file (x.o).


  ____________________
 |            ------- |
 |            | x.h | |
 |            ------- |
 |            /     \ |
 |           /   ___ \|
 |          /   |     \
 |   ---------  |  ------------
 |   | x.cpp |  |  | main.cpp |
 |   ---------  |  ------------
 |        |     |        |
 |        |     |        |
 |        |     |        |
 |   ---------  |  ------------
 |   |  x.o  |  |  |  main.o  |
 |   ---------  |  ------------
 |________ \____|      /
            \         /
             \       /
             ---------
             | a.out |
             ---------




A good idea to imagine, how we would like to use our class.


An example: class date, store, retrive and compare date values.





// 
// datemain.cpp
// 

#include <iostream>     // standard header files
#include "date.h"       // date.h for date class

int main()
{
  // date d;    // syntax error: no default constructor

  date d(1);
  while ( std::cin >> d )  // read date until eof
  {
    d += 40;    // add 40 days
    std::cout << d << std::endl; // print result 
  }
  std::cin.clear(); // clear eof()

  date d2( 2015, 3);  // this should be 2015.03.01
  d = d2;       // assignment, now d is 2015.03.01
  std::cout << d << " == " << d2 << std::endl;

  date d3("2015.03.23");
  std::cout << "d3++ == " << d3++ << std::endl;
  std::cout << " d3  == " <<  d3  << std::endl;
  std::cout << "++d3 == " << ++d3 << std::endl;
  std::cout << " d3  == " <<  d3  << std::endl;

  d3.setDate(2000,1,1);
  std::cout << "d3.setDate(2000,1,1) == " << d3 << std::endl;
  d3.setYear(2015).setMonth(3).setDay(23);
  std::cout << "d3 == " << d3 << std::endl;

  std::string s;
  while( std::cin >> s )
  {
    try
    {
      std::cout << s << " == ";
      date d4(s.c_str());    // test constructor from char*
      std::cout << d4 << std::endl;
    }
    catch( std::exception& e )   // catch exception
    {
      std::cerr << e.what() << std::endl;  // what() is inherited from 
                                           // std::exception
    }
  }
  return 0;
}




// 
// date.h
//


#ifndef DATE_H
#define DATE_H

#include <iostream>
#include <stdexcept>  // for std::logic_error

/* 
 * simple date class 
 *
 * just an example for object-oriented programming
 * for real programs, use std::chrono from <chrono>
 *
 */

class date
{
public:
  /* exception to express bad date */
  class bad_date_t : public std::logic_error // inherited std::exception 
  {
  public:
    bad_date_t(const char *s) : std::logic_error(s) { }
  };

  /* constructors */
  date( int y, int m=1, int d=1) { setDate( y, m, d); }
  date( const char *s);   /* convert from char* */

  /* accessors */
  int  getYear()  const { return year; }
  int  getMonth() const { return month; }
  int  getDay()   const { return day; }

  /* setters */
  date&  setYear( int y)  { year  = y; return *this; }
  date&  setMonth( int m) { month = m; return *this; }
  date&  setDay( int d)   { day   = d; return *this; }

  void  setDate( int y, int m, int d);

  /* additive */
  date&  next();
  date&  add( int n);
  /* prev(), ... */

  /* operators */
  date& operator++()       { return next(); }
  date  operator++(int)    { date curr(*this); next(); return curr; };
  date& operator+=( int n) { return add(n); }
  /* operator--(), ... */

  /* io */
  void get( std::istream& is);
  void put( std::ostream& os) const;

private:
  /* helpers */
  void checkDate( int y, int m, int d);

  /* data members */
  int year;
  int month;
  int day;
};

/* global operators */
bool operator<( date d1, date d2);

inline bool operator==( date d1, date d2) { return !(d1<d2 || d2<d1); }
inline bool operator!=( date d1, date d2) { return d1<d2 || d2<d1; }
inline bool operator<=( date d1, date d2) { return !(d2<d1); }
inline bool operator>=( date d1, date d2) { return !(d1<d2); }
inline bool operator>( date d1, date d2)  { return d2<d1; }

/* global io operators */
std::istream& operator>>( std::istream& is, date& d);
std::ostream& operator<<( std::ostream& os, const date &d);

#endif /* DATE_H */



//
// date.cpp
//

#include <iostream>
#include <cstring>
#include <cstdlib>

#include "date.h"

using namespace std;

namespace /* anonym namespace, visible only in this source */
{
  const int day_in_month[] =
       { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
}

/* constructor */
date::date( const char *s)
{
  /* strchr and strrchr from <cstring> */
  const char *p1 = strchr( s, '.');
  const char *p2 = strrchr( s, '.');

  if ( p1 && p2 && p1 != p2 )
  {
    /* atoi from <cstdlib> */
    int y = atoi(s);
    int m = atoi(p1+1);
    int d = atoi(p2+1);

    setDate( y, m, d);
  }
  else
  {
    throw bad_date_t("Wrong string");
  }
}

void date::setDate( int y, int m, int d)
{
  checkDate( y, m, d);

  year  = y;
  month = m;
  day   = d;
}

/* additive */
date& date::next()
{
  ++day;

  /* TODO: leap year */
  if ( day-1 == day_in_month[month-1])
  {
    day = 1;
    ++month;
  }
  if ( 13 == month )
  {
    month = 1;
    ++year;
  }
  return *this; // return reference to *this object 
}

date& date::add( int n)
{
  for (int i = 0; i < n; ++i)
  {
    next(); /* KISS */
  }
  return *this; // return reference to *this object 
}

/* input-output */
void date::get( std::istream& is)
{
  int y, m, d;
  if ( is >> y >> m >> d ) // have to check for success
  {
    setDate( y, m, d);
  }
}

void date::put( std::ostream& os) const
{
  // better to build on accessors;
  os << "[ " << getYear()  << "."
             << getMonth() << "."
             << getDay()   << " ]";
}

/* helpers */
void date::checkDate( int y, int m, int d)
{
  if ( 0 == y )                 throw bad_date_t("Bad year");
  if ( m < 1 || m > 12 )        throw bad_date_t("Bad month");
  if ( d < 1 || d > day_in_month[m-1] )  throw bad_date_t("Bad day");
}


/* ==============================  Globals ========================= */


/* global operators */
bool operator<( date d1, date d2)
{
  return (d1.getYear() <  d2.getYear())
      || (d1.getYear() == d2.getYear() && d1.getMonth() <  d2.getMonth())
      || (d1.getYear() == d2.getYear() && d1.getMonth() == d2.getMonth()
                                      && d1.getDay()   <  d2.getDay());

}

/* io operators built top on get and set */
istream& operator>>( istream& is, date& d)
{
  d.get( is);
  return is;  /* important to chain reads */
}

ostream& operator<<( ostream& os, const date &d)
{
  d.put( os);
  return os;    /* important to chain writes */
}


//////////////////////////////////////////////////////////



# Components can be compile separatedly:

$ g++ -ansi -pedantic -Wall -c datemain.cpp

$ g++ -ansi -pedantic -Wall -c date.cpp



# then linked together:

$ g++ datemain.o date.o



# and run:

$ ./a.out