Toggle Menu

Compilation & Namespace


Compiling The Program

In C++, we can separate the specification of what the class does from how it is implemented. In doing so, if we change the implementation of the class, then we only need to recompile the file containing the class implementation. Other files that might be using this class need not be changed or recompiled. This is an important principle of encapsulation.
  1. All member vars should be private
  2. Basic class operations should be one of:
    • Public member functions
    • Friend or ordinary functions
    • Overloaded operators
    We grouped the class definition and the function declarations/prototypes together in the interface The interface is what clients see and is placed in a header file (ends with a .h. Other files that use this class will have to include it with the include directive: #include "filename.h").
    The double quotes "" indicates that it is a programmer-defined file whereas angle brackets <> indicates a built-in library.
  3. Make class implementation unavailable to clients. The implementation consists of the function definitions, overloaded operator definitions, and other helper functions. The implementation is placed in an implementation file (ends with a .cpp or .cc). The implementation file must include the header file.

Compiling The Program

At compilation, only the implementation and application (driver) file, the file containing the main function, are compiled but not the interface file. The interface file is not compiled because the compiler assumes that the contents of the interface file is contained in the implementation files.
The compilation process invokes a preprocesser that reads the include directive and replaces it with the text in the corresponding interface file. Once compiled, the linker connects the implementation and application files so they can work together.

ifndef

We note that a problem might arise when the same interface file is included multiple time across multiple files. Some of these files might include others of these files, and we end up with the same header file being included multiple times in the same file. C++ does not allow redefinition of classes. To solve this:
  1. #define FILE_H
    This includes FILE_H in a list to indicate that it has been seen.
  2. #ifndef FILE_H
    This checks whether FILE_H is in the list. If so, it skips everything until #endif
#ifndef FILE_H
#define FILE_H
class C {};
#endif
* Alternatively, you can use #pragma once instead of the above to accomplish the same results.

Namespaces

Namespaces are a collection of name definitions, such as class and variable declarations. Programs use many classes and functions that might have same names. Namespaces help solve this by allowing us to turn on/off the ones we want.
The global namespace is everywhere that isn't in a specific namespace.

Creating A Namespace

To place code in a namespace, we place it in a namespace grouping: namespace Name_Space_Name {}

Using Directive

The using directive makes all definitions in std namespace available. The same name can be defined in two different namespaces but we can only use one of those namespaces at a time. If a name is defined in multiple namespaces, we must use the scope resolution operator :: to specify which namespace is used. The using directive applies only to the block from where it is placed.
{
  using namespace NS1;
  myFunction();
}
{
  using namespace NS2;
  myFunction();
}

Using Declaration

A using declaration can also be used to specify individual names from a particular namespace. i.e. using Name_Space::One_Name;
This makes One_Name from the namespace Name_Space available but not the other names in Name_Space.

Using Declaration vs. Using Directive

  1. Using declaration makes only one name in the namespace available to your code, while a using directive makes all the names in a namespace available
  2. Using declaration introduces a name into your code so no other use of the name can be made, while a using directive only potentially introduces the names in the namespace. i.e.
    namespace NS1 { myFunction(); }
    namespace NS2 { myFunction(); }
    
    using namespace NS1;
    using namespace NS2; // legal as long as myFunction is not used
    
    using NS1::myFunction;
    using NS2::myFunction;  // illegal
    
Namespaces are generally named with unique strings like last names as it reduces the chance of other namespaces having the same name.

Unnamed Namespaces

Unnamed Namespaces can be used to make definitions local to a compilation unit (a file along with all the files included by the include directive in it). Each compilation unit has one unnamed namespace. i.e. namespace { }

Global vs. Unnamed Namespaces

Names in both global and unnnamed namespaces may both be accessed without a qualifier. However, here are some differences:
  • Global Namespace
    • no namespace grouping
    • global scope
  • Unnamed Namespace
    • has namespace grouping, just no name
    • local scope

Hiding Helper Functions

Helper functions have low-level utility and aren't for public use. There are 2 ways to hide them:
  1. Make them a private member function if it naturally takes a calling object
  2. Place in unnamed namespace if function does not need a calling object

extern Keyword

The extern keyword is used to tell the compiler that the variable is declared in another module outside the current file's scope. The linker then finds this declaration and points this extern variable to the correct location. This allows multiple files to work with the same variable. extern variables do not have space allocated to them. e.g. extern int i;