|
|||||||||
UPDATED ON 7/14 at 7pmWhy use separate compilation?When you write a class you are writing a module that needs to be reusable. Certainly, the most direct way to reuse code would be to cut and paste it wherever you find that you need it. Unfortunately, this is unwieldy and sometimes it isn't clear what should be copied and what should be left behind. The correct approach is to employ separate compilation by writing your class, compiling it apart from your program that uses the class.You've seen how to write
and use the Date class in one monolithic
file. The overall layout looks like this:
This works, but the problem
(as stated earlier), if there is another program where Date objects would
be useful, it's a pain to do so.
What is separate compilation?The solution is to define what a Date is in a different file from where it is used. We will reorganize the Date class in this way. The first thing we need to do is write a "header" file (ending in .h) for the class:
The reason we need the conditional compilation directives is because the preprocessor needs to know that if the Date header file is included from some other module in the program, then it doesn't need to do this declaration again (in fact, it would be an error to do it twice). See section 5.2.2 in your book for more information on how this works. The header file is much like
a function prototype (in fact, it contains three function prototypes, if
you look closely you'll see them) because it provides enough information
to use Dates, but that's it. It does not contain the code
for how the class operates. That needs to be done in a different
file:
This file contains the "guts" of the Date class, in that all of the methods are defined here. One property of a well-written class is that someone who wants to use the class should not need to see this file. In other words, everything we need to know to use Dates should be present in the header file (figure 2). Notice how the header file is included here? As you probably remember, the preprocessor will do a direct substitution of the header file above (date.h) and put it right where you see the #include directive. We also include <iostream> because of the use of cin and cout, and the out and extraction operators. Sidenote: the iostream header file also has the conditional compilation directives in it because clearly, iostream is going to be used all over the place. We'd get errors if it was constantly being redeclared. The reason we did this is because now we can compile date.cpp and date.h independently. By doing this, we have essentially set up our on mini-library for Dates. The linker would be responsible for bringing the binary code into the picture (whereas before it was all done in one file and not linked in). Ok, now how do we use the
Date class? It's easy, just tell your main() program you want to
use dates by adding the appropriate #include, and you're ready to go!
Think about what the #include
"date.h" gives you: it "plugs" the header file in there, thus letting
the compiler know that Dates can be used in the program. The code
that does everything is not there, but it comes later when the libraries
are linked in. It's all pretty clever, really. Now anyone
who needs a Date object just needs to get their hands on date.h
and date.cpp and they are ready to go! In fact, they don't
technically need date.cpp, but only the object file holding the
compiled version of the methods. This is how it is done in industry,
frequently, because people don't want others messing with their source
code. This would be impossible without separate compilation.
Separate compilation in BorlandHere's how you set this all up in Borland.
|
|||||||||
© 2000-2001 Jim Skrentny, University of Wisconsin |