Activity 9-1 - Separate Compilation



C++ has facilities for dividing a program into parts that can be kept in different files.  These files can be compiled separately and then linked together when the program is about to run. One thing that is commonly done in programs with classes is that the class definition is placed in one file and the implementation in another.  The ADT (Abstract Data Type) is a class that is designed to separate the interface and the implementation of the class.  All class definitions should be ADTs.  If you wish to define a class as an ADT, then you should separate the specification of how the class is used from the details of how the class is implemented.  The separation must be such that you can change the implementation and any program that uses the class can still use it without a need to make any change.

In order to illustrate how the separate compilation of different pieces is done, let's look at program P84.cpp and see how we can break it in several pieces.  Each piece is shown with a different color.

// This and the following 5 lines will go to the main program, main_prog.cpp
// Additional include statements should be added
// P91.cpp - This program is a driver written to demonstrate how we can use a
// class inside another one.
#include<iostream>
using namespace std;

// This part will go to ID.h file
class ID
{
    public:
        ID( );
        ID(int, int, int);
        void display();
    private:
        int left;
        int middle;
        int right;
};

// This part will go to Loan.h file
class Loan  // Loan class definition
{
   public:
     Loan( );
     Loan(ID id, float amount, float rate, int term);
     void set( );
     float payment( );
     void display( );
   private:
      ID id;  // assume an unique integer in three integer parts
      float amount; // $ amount of the loan
      float rate; // annual interest rate
      int term;  // number of months, length of the loan
 };

// This part will go to the main program, main_prog.cpp
int main( )
{
    Loan loan1(ID(111,22,4444), 2300, 5.5, 48);  // initialize to values given

 Loan loan2;

    cout << "Display loan1 \n";
    loan1.display();

    loan2.set( ); // set the values
    cout << "Display loan2 \n";
    loan2.display();

    return 0;
}

// This part part will go to the ID.cpp file
ID::ID( )
{
   // use default values
}

ID::ID(int l, int m, int r)
{
     left = l;
     middle = m;
     right = r;
}

void ID::display()
{
     cout << right << "-" << middle << "-" << right << endl;
}
 

// This part will go to the Loan.cpp file
Loan::Loan( )
{
}

Loan::Loan(ID I, float am, float rt, int trm)
{
   id = I;
      amount = am;
      rate = rt;
      term = trm;
}

void Loan::set( )
{
   int l, m, r;
      ID temp_id;
       // Initialize the loan1 object
      cout << "Enter the left part of the loan ID \n";
      cin >> l;
      cout << "Enter the middle part of the loan ID \n";
      cin >> m;
      cout << "Enter the right part of the loan ID \n";
      cin >> r;

      id = ID(l, m, r);

      cout << "Enter the amount of this loan \n";
      cin >> amount;

      cout << "Enter the annual interest rate of this loan (in %) \n";
      cin >> rate;

      cout << "Enter the term (number of months, length of the loan) \n";
      cin >> term;
}

void Loan::display()
{
     id.display();
     cout << amount << endl;
     cout << rate << endl;
     cout << term << endl;
}

As we mentioned before, the definition of a class will be placed in one file and the implementation of it in another file.  In the above program, we have two classes, thus, we will have four files;  two .h files that keep the class definition and two .cpp files that keep the implementation. All together we will have 5 files, 3 .cpp files and 2 .h files.  Here is the list of file names:
1) main_prog.cpp    This is the main program that has the core of implementation and computation in it
2) ID.cpp                   This file keeps the implementation of class ID
3) ID.h                    This file keeps the definition of class ID
4) Loan.cpp               This file keeps the implementation of class Loan
5) Loan.h                This file keeps the definition of class Loan

As you may expect, once you separate the files, you need to let the main function know where to get the information on each class.  Also, when you use objects of a different class inside a class, you need to know the definition for the class that is being used.  In order to do this we will use the include directive.  For example, now that we have two different files for two classes, at the top of main function we need to have:

#include  "ID.h"
#include  "Loan.h"

Also, we need to include the ID.h in the Loan file, because Loan class uses the ID class.  There is something you need to be aware of when you include a .h file at the top of a program, it is as if you have listed the contents of that file there.  As you can imagine, if you include something twice, you will get an error.  So if a .h file is already included in the Loan.h file, and then you include Loan.h and ID.h at the top of main, you seem to have the ID.h file listed twice.  To fix this problem, we will somehow let the compiler know that the ID.h has been seen in Loan.h so it won't get listed again.  So, for the .h file that may be listed more than once, we include a flag to avoid listing things twice.  The flag has three parts, commented below with //1, //2, and //3.  You do not need to include the comments in your version.

#ifndef ID_H   //1
#define  ID_H  //2

#include<iostream>

class ID
{
    public:
        ID( );
        ID(int, int, int);
        void display();
    private:
        int left;
        int middle;
        int right;
};

#endif  // 3

What we do is test to see whether the ID_H has been visited, or defined.  If the .h file has not beenn defined (#ifndef ID_H), the definition following this statement is used to define the class (#define).  If it has been defined, everything between the #ifndef ID_H and #endif is skipped.  The format is the same for all other .h files, for example:

In the Loan.h file
#ifndef Loan_H   //1
#define  Loan_H  //2
 ....
 ....
#endif  // 3

Exercise 9.1
Write the above program in five different files as described by the comments at the top of each section.  Once you have created the 5 files, include the ID.h and Loan.h file in the main.  Make the changes in the other .h files so they will be visited twice.  Once you have made all these changes, compile and link all parts using the following command:

% g++  main_prog.cpp  Loan.cpp  ID.cpp

This will create an a.out file that should produce the same results as the program that had all pieces together.