Team 2550
Technical Documentation
|
|
As you write larger amounts of code, it becomes useful to distribute it among various files. Header files can contain constants, function prototypes, and various other information that is not directly compiled. That way, you can easily tell the compiler that something exists without actually having the code. This is how libraries work. The object code for the library is stored in a special file that contains the bindings to the C or C++ header and the binary code. When you include the header and tell the compiler where to look for the library, you can write code that utilizes the library.
Namespaces allow you to organize your code as if it were in a file system. The entire standard library of C++ has been placed within a namespace already: std
. The idea is to allow naming conflicts: for instance, two graphics libraries may have the same function that does basically the same thing, but it was written by different people.
If you have looked at any code online, you may have noticed that instead of including, for instance, <cmath>
, they included <math.h>
. Functionally, these are the same, but the .h version is obsolete. Due to the fact that C does not have namespace support, C++ also has all of the old header files (which are not a part of the std
namespace) in order to maintain compatibility.
A namespace is very easy to declare and use, here is some example code.
The ::
is called the scope resolution operator. A namespace creates a new scope that can be accessed from anywhere using the ::
operator (assuming that the namespace is defined in that file). ::
is run before all of the arithmetic operators. See the Scope for a refresher.
If you had to put all of your code in a single file, things would get messy very quickly. In addition, all of your namespace declarations and function prototypes would have to go to the top of the file. This is very unwieldy and would make it difficult to reuse code. Fortunately, you can put this extra information in header files.
You can move the namespace declaration and all of your function prototypes to a header file (like the ones that you #include
from the standard library.
using namespace ...
line in a header. If you do, that setting will also apply to any file that includes the header. This can lead to naming conflicts.std::string
here, the string
datatype is a part of std
and there is no using namespace std;
line.There would also be two other files. One that has the definitions for the functions in the namespace (mycode.cc
) and one that contains the main
function (projectname.cc
). Both would have the line #include "mycode.hh"
near the top.
#include <header>
searches in the system location for headers and #include "header"
searches in the location of the source file containing main()
.The purpose of a header file is to state that something exists before it is actually defined. This allows you to easily enable a group of functions and namespaces in some files and not in others. Typically, a project will look like this...
project.cc util.hh util.cc customdatatype.hh customdatatype.cc morefunctions.hh morefunctions.cc
Anyways, you get the idea. Related functions go in their own files and that file has a corresponding header.
.cc
or .cpp
for C++ source files.hh
or .hpp
for C++ headers.c
for C source files.h
for C headers.h
file.The C++ preprocessor is basically a programming language that allows you to control how the code is compiled.
All preprocessor directives (commands) are prefixed with a #
:
#include
: literally copies and pastes code from one file into another at the location the directive was placed#define CONSTANT
or #define CONSTANT VALUE
: defines a constant that can be accessed during the preprocessing stage of the compilation#undef CONSTANT
: un-defines CONSTANT
#ifdef CONSTANT
: checks to see if a constant is defined#ifndef CONSTANT
: the opposite of #ifdef
#elif EXPRESSION
: an else if
statement#else
: self explanatory#endif
: the code between this and a #ifdef
or #ifndef
is compiled only if the statement evaluates to true#warning message
and #error message
: makes the compiler raise an error or warning with a custom message.CONSTANT
has nothing to do with const
data types in C++. However, it is worth noting that placing DEFINED_VALUE
anywhere in the code will "paste" the value of the defined constant in that location.The above commands should be sufficient to explain why the #ifndef
at the top of header files is necessary. Basically, here is what it says...
if HEADER_NAME is not defined { define HEADER_NAME compile this code ... } else it is already compiled, don't do anything
_cplusplus
. Allowing you to selectively compile code based on whether it is being used in a C or C++ environment.