Can someone please explain how this works in C++?
Hi,
First, compiling in C++ is done in three steps: precompilation, compilation and linking. The precompilation is:
- looking for "#include" directives
- expanding macros
- processing conditional compilation
For 1., when you include a file, the code in the file is "pasted" into the compiled file from the first file matching the provided name found in the include path. The include path is specified to the compiler as input parameters (for gcc that is done with -I, so you can have gcc file.cpp -I. -I/usr/include and so on).
This "pasting of the code" can create problems, as one file can be (and usually is) included multiple times, in different files in your project. This means that after the preprocessor has done it's job, you might encounter multiple definitions for the same symbols. To avoid compiler errors due to this, you use an "include guard" construct that looks like this:
#ifndef SOME_UNIQUE_SYMBOL
#define SOME_UNIQUE_SYMBOL
// all the code in your file goes here
# endif // SOME_UNIQUE_SYMBOL
In this way, the first time the code is added (on the expansion of the #include by the precompilation process) it will be parsed (as SOME_UNIQUE_SYMBOL is undefined). The second time, the code is added but will not be parsed (as SOME_UNIQUE_SYMBOL should already have been defined the first time).
Microsoft C++ compilers define a #pragma once
dirrective that you can use as the first line in a header file. This ensures that the precompiler will only include the file once (effectively replacing the #ifdef
/ #define
/ #endif
combo).
Concretely in your example, your #endif
should be the last line in the file.
This "pasting of the code" is also the reason why you separate declarations from definitions in C++: you place all declarations in header files (traditionally named something.h) and the definitions in source files (traditionally named something.cpp) and you only include header files.
Your header files should always be minimal. That is, they should only include declarations and enough #include directives for everything in the header file to be recognized (function and class names, constants and defines and so on).
Your example should be:
//Library.h
#ifndef LIBRARY_H_
#define LIBRARY_H_
class Book; // forward declaration, see below
class Library
{
public:
Library();
~ Library();
private:
Book *database;
};
#endif // moved as the last line of the file
In this example, the compiler will need to know what is the size of the Library class when compiling it. For this requirement, it needs to know how big each of the member variables of Library is.
In your case you only have a pointer to a book, so the size will be four bytes (or eight or something else, depending on processor architecture).
You still need to tell the compiler that "Book is a class" and you have two ways to do that: either use the forward declaration, or include the header file that defines the Book class (replace the class Book; code with #include "Book.h"
.
The forward declaration tells the compiler "Treat any Book token in the source as a class. You will find out the definition of the class later".
If Book will not be found on linking (i.e. compiled as a separate object file and linked together with Library) the compiler will raise a linker error.
If you use the #include
you can also use a Book instance instead of a Book pointer in the header declaration (as when including it, you ensure the size of a Book class can be computed by the compiler when parsing Library class.
If you use the forward declaration, you will still have to use the #include in the source file of the Library class (in the .cpp class) where you actually use methods from the Book class.