Advanced C++ - Part IIIb (Creating libraries)


The programs that we've seen so far are not wrong but they can't be called as 100% C++ programs either. The reason is because we've been making use of header files (such as iostream.h etc...). Making use of these .h files is more similar to C programming. Of course it isn't wrong to use them in C++ but there is a better method provided in C++. This method makes use of namespaces.

Instead of # include <iostream.h> we shall use the following two lines:

#include <iostream>
using namespace std;

Firstly take note of the fact that there is no ‘.h’ in the include statement. This is the format of the new style headers used in C++. They do not use .h files. Old C++ compilers may not support namespaces. In case you are using such a compiler then you have to stick to the old method of #include with the ‘.h’ extension. But all the latest C++ compilers will support namespaces and they will also support the old style headers.

When C++ was created it used header files like those used in C programming. But then changes were made. Though it still supports the old header files, they are not recommended. You know that iostream.h is a file. C++ created a new style of its own. In this method we do not specify filenames. Instead it is a method that makes sure that appropriate definitions required by the C++ library have been declared. The new style headers are not filenames and hence the .h extension is left out.

Multiple File C++ Programming

So far we’ve been writing programs within one source file. The entire program (including class declarations, functions etc.) was written in one single *.cpp file. This file was compiled and run to check the output. In this section I would like to explain the process by which an executable file is created from our C++ source file.

Let’s assume that we’ve written a source file called test.cpp. What are the steps involved after that? Broadly you can say that four people are involved:

As mentioned earlier, the preprocessor will search for the preprocessor directives. It will convert these directives into C++ coding. In other words, the include header files will be inserted into your source file. If you have used macros, they will be substituted in the corresponding places.

Next, the compiler takes over. The compiler will read through the whole program, and in case it finds any problems while compiling, it will display compile time errors. Otherwise it will convert your source code into assembly language code.

The assembler will finally convert your assembly language code into machine language (i.e. into language that your computer can understand).

What is produced by the assembler is known as an object module (or a single translation unit because the source code has been translated into object code). Is the process over?

Even in a most basic C++ program we make use of other library functions and objects. Thus there are a few other object modules that are related to your C++ program. Only when these modules are linked with your object module, can the program work. The linker takes care of this aspect. All the different units are linked together to form the final executable program.

So, nowadays when we say a compiler, for example the Turbo C++ compiler, it usually contains all the required parts (a compiler, preprocessor, linker and assembler). Thus you needn’t worry about these individual parts of the compiler. But when you do create a multiple file C++ program, you should beware that just because all your individual files compile successfully doesn’t mean that they will be linked properly. You can get linker errors (possibly you forgot to include some header file or something like that). The question arises, why should we go in for multiple file programming?

When a program is very complex it is always advisable to break up the program into smaller units. In C programming, we would define the functions in a separate header file and then include this header file in our source file. In C++ we are bothered with classes. So, instead of functions, we will define classes separately. What we will do is to define the class in a header file. We will not define the member functions in this file (we will only declare all the member functions). The definitions will be done in a *.cpp file using the scope resolution operator. Now when you want to write a program using that class, you will simply include the header file in your source code. What about compiling? Header files cannot be compiled. But now you have two *.cpp files (one with the member function definitions and the other is your source file). We will compile both files separately and then when you build your project the linker will link up both the object modules together. Might seem a bit confusing but an example should make things easier to understand.

One more point to remember: Member functions are defined in a separate *.cpp file. This is usually referred to as the implementation. The idea is to keep the implementation of the class separate from the declarations.

Creating a Multiple File Program

The example demonstrated below has been tried in Turbo C++ as well as in VC++. Other compilers will also have similar options available.

First of all we shall take a look at how to create a multiple file program in Visual C++ (later we’ll deal with Turbo C++). Click on File and then choose New. You’ll have a lot of options like (File, Project, Workspace etc…). Choose the Projects tab and in that you’ll have numerous choices available. Choose Win 32 Console Application from the list and give a suitable name. Let us assume that the name is given as carcheck. Choose the option which says "Create New Workspace" and then click on Finish/Ok. If you are using Visual C++ 6.0, another menu will pop up asking what type of application you want to create (whether you want an empty project or whether you want a "Hello World" application etc.). Choose "Empty Project". The new workspace will be created with the name as "carcheck". You will have two tabs with the labels "Class View" and "File View". This will give you an idea as to what are the classes and files present under your current project. Click on the FileView tab and you’ll see that there are no files there.

Now again go to "File" and choose "New". This time create a new C++ header file. Give a suitable name (here we have named it as ‘car’). Now you’ll have a new header file called car.h within the "FileView". This file will be empty and we shall now declare our class within this file.

//car.h
#include <iostream>
using namespace std;

class car
{
private:
    char color[20];
    int speed;

public:
car( );
void input( );
void display( );
~car( );
};

As you can see, all the functions have only been declared in the file car.h (we have not defined them here).

Next, go to "File", "New" and create a new C++ source file. Name this file as car.cpp. Open the file in your editor window and type in the following:

//car.cpp – we will define the various functions in this file.

#include "car.h"

car::car( )
{
cout<<endl<<"New car created.";
}

void car::input( )
{
cout<<endl<<"Enter the color : ";
cin>>color;
cout<<endl<<"Enter the top speed : ";
cin>>speed;
}

void car::display( )
{
cout<<endl<<"The color is : "<<color;
cout<<endl<<"The top speed is : "<<speed;
}

car::~car( )
{
cout<<endl<<"Your car is destroyed.";
}

Now since this is a *.cpp file, you can compile this file. Go to the "Build" option and choose "Compile car.cpp". After successful compilation, we shall now proceed to create our main source file (the file containing the program). Create another new C++ source file and name it as main.cpp. You might be wondering why the following was used:

#include "car.h"

in the car.cpp file while the following statement:

#include <iostream>
using namespace std;

was used in the car.h file.

car.h is a header file created by us. So, it is present in the directory where we are doing our project. But <iostream> is present in the compiler’s include directory. Hence for car.h we include it using the double quotation and for iostream we use the angle brackets.

//main.cpp
#include "car.h"
int main( )
{
car mine;
mine.input( );
mine.display( );
return 0;
}

Now, compile this file (main.cpp). After compilation, you can go to "Build" and choose "Build carcheck.exe". It is now that the linker will work and link up everything. After this, go back to "Build" and choose "Execute carcheck.exe".

The output will be:

New car created.
Enter the color : red
Enter the top speed : 300
The color is : red
The top speed is : 300
Your car is destroyed.

Remember: The header car.h already include <iostream>, so there is no need for you to include <iostream> again in the file main.cpp.

Beware: When you are linking many object modules together, only one of them should have the main ( ) function. In the above case we created two object files from car.cpp and main.cpp but only main.cpp had the main ( ) function.

By the way, in Visual C++ workspace files are stored with the extension *.dsw.

Preventing multiple inclusions of Header files in a program:

Usually when creating header files, the programmer will provide a provision so that the header file is not included in the source code more than once. To do this, we can make use of the preprocessor directives. The modified ‘car.h’ file will be:

#ifndef CAR_H
#define CAR_H
#include <iostream>
using namespace std;

class car
{
private:
    char color[20];
    int speed;
public:
car( );
void input( );
void display( );
~car( );
};

#endif

The header file be included within the source code only if CAR_H has not been defined. This prevents multiple inclusions of the ‘car.h’ in a program. CAR_H actually stands for ‘car.h’ (you cannot use the dot in preprocessor directives and thus have to use an underscore). You can use car_h or CAR_H (programmers usually prefer to use the latter).

If you are using Turbo C++

In Turbo C++, the above process is much easier. First of all create 3 files as done previously (car.h, car.cpp and main.cpp). Next you have an option that says "Project". Click on that and choose "Open Project". Since you still haven’t created a project, just type in some name for the project (ex: carcheck.prj) and click open. (In Turbo C++, project files have a *.prj extension). You’ll see a new project window at the bottom of the screen. Again click on "Projects" and choose "Add new item". A list of all the files will pop up on your screen. Locate the two files (car.cpp and main.cpp) and click on "Add". After adding both the files, choose "Done". Now both your *.cpp files have been added to the project. Next, you have to compile both these files. Do the compiling as you normally would. Open the file car.cpp and then click on "Compile". Then open main.cpp and compile this file also. Now if you look at the project window at the bottom of the screen you’ll notice that there are two items listed:

car.cpp
main.cpp

Once you compile the two files, the project window will also display the number of lines in each file, whether they have any data etc.

Next choose "Build All" from the "Compile" option menu. Once successfully done, you can choose "Run" and your program will execute.

To summarize the concept of multiple file programming:

All C++ classes can be divided into two main parts:

Class Declaration: This is also called as the interface of the class. It just contains information about the data members and the various functions that are available in the class. This is usually in the header file (in our case it was in car.h).

Class Implementation: This defines all the member functions that were declared in your header file (in our case it is car.cpp).

This will help you to hide the implementation from the user. Even though you may change your implementation, the class interface will remain the same.


The keyword ‘extern’

The ‘extern’ keyword was briefly mentioned in the chapter on data types. This is basically another storage class specifier (the others are static, auto and register) which you can use with your data types when you declare them.

When you develop a project consisting of many separate files there is a good possibility that you will be using global variables. The question arises, "Should we declare and define global variables in each of the files?" (because each *.cpp file will be compiled separately). This is not allowed in C++ and it is bad programming practice to declare and define the same global variable in more than one place. Hence in C++ we have ‘extern’. This will only declare a variable, it will not define it. Only when we define a variable will the compiler allot memory for the variable. Usually declaration and definition of a variable occur at the same time. But when we use the extern specifier (which stands for external), we tell the compiler that this is only a declaration (the definition of the variable is done in some other file). Thus usually all global variables are defined in one separate file and in all the other places we only declare the variable.

The syntax is:

extern data-type variable-name;

The linker will take up the responsibility of resolving all the references made to the external variable.

Another use of Extern:

By default, C++ compilers will link all your functions as C++ functions. All C++ compilers make use of name mangling. When the compiler reads through the source code and encounters a function name, it stores the details about the function in a table (called a symbol table). For example if we have a function:

    void sub (int, int);

the compiler will store this function in its symbol table. But functions in C++ are name mangled, i.e. the function name stored by the compiler is not the same one as given by us. The compiler may store it as:

    sub_int_int

Thus whenever the compiler encounters a function call to sub ( ) it will retrieve the appropriate definition for the function at compile-time. Name mangling permits C++ to implement function overloading. Let us say we have another function with the same name ‘sub’:

    void sub (double,double);

The compiler will store this as

    sub_double_double

Thus whenever there is a statement calling the function sub ( ), the compiler will check the data types of the arguments and call the correct function.

C compilers do not implement name mangling and thus they do not support function-overloading. Different C++ compilers (supplied by different vendors) may implement name mangling in a different way but the bottom-line is that all C++ compilers implement name mangling. Other languages mostly do not use name mangling (C compilers do not mangle names).

Let us suppose that you have written a few functions in C and have compiled them using a C compiler. Now in your C++ program you want to use those C functions. Is it possible? C++ will mangle all the function references and the mangled names will not be the same as the original C function name. Thus the linker won’t be able to match the function call (compiled in C++) to the function definition (compiled in C). To overcome this problem we need to tell the C++ compiler, "Do not mangle this function since it is not a C++ function".

The extern keyword can be used for this purpose.

The syntax is:

    extern "name-of-the-language" function

Beware: You cannot use this within a function (it wouldn’t make any sense to do so). Always make such declarations global.

Example:

    extern "C" int display ( ); //global declaration

The C++ compiler now knows that the function display( ) is a C compiled function and so it won’t mangle the function name display( ). Sometimes if you have many functions that you want to link as a different programming function then you can do it as follows:

extern "name-of-language"
{
//function declarations/headers can also be included here
}


Go back to the Contents Page 2


Copyright © 2004 Sethu Subramanian All rights reserved.