官术网_书友最值得收藏!

Header files

The most common use of the preprocessor is the #include directive, intended to include header files in the source code. Header files contain definitions for functions, classes, and so on:

// file: main.cpp 
#include <iostream>
#include "rect.h"
int main() {
Rect r(3.1, 4.05)
std::cout << r.get_area() << std::endl;
}

Let's suppose the header file rect.h is defined as follows: 

// file: rect.h
struct Rect
{
private:
double side1_;
double side2_;
public:
Rect(double s1, double s2);
const double get_area() const;
};

The implementation is contained in rect.cpp:

// file: rect.cpp
#include "rect.h"

Rect::Rect(double s1, double s2)
: side1_(s1), side2_(s2)
{}

const double Rect::get_area() const {
return side1_ * side2_;
}

After the preprocessor examines main.cpp and rect.cpp, it replaces the #include directives with corresponding contents of iostream and rect.h for main.cpp and rect.h for rect.cpp. C++17 introduces the __has_include preprocessor constant expression. __has_include evaluates to 1 if the file with the specified name is found and 0 if not:

#if __has_include("custom_io_stream.h")
#include "custom_io_stream.h"
#else
#include <iostream>
#endif

When declaring header files, it's strongly advised to use so-called include-guards (#ifndef, #define, #endif) to avoid double declaration errors. We are going to introduce the technique shortly. Those are, again, preprocessor directives that allow us to avoid the following scenario: type Square is defined in square.h, which includes rect.h in order to derive Square from Rect:

// file: square.h
#include "rect.h"
struct Square : Rect {
Square(double s);
};

Including both square.h and rect.h in main.cpp leads to including rect.h twice: 

// file: main.cpp
#include <iostream>
#include "rect.h"
#include "square.h"
/*
preprocessor replaces the following with the contents of square.h
*/
// code omitted for brevity

After preprocessing, the compiler will receive main.cpp in the following form: 

// contents of the iostream file omitted for brevity 
struct Rect {
// code omitted for brevity
};
struct Rect {
// code omitted for brevity
};
struct Square : Rect {
// code omitted for brevity
};
int main() {
// code omitted for brevity
}

The compiler will then produce an error because it encounters two declarations of type Rect. A header file should be guarded against multiple inclusions by using include-guards in the following way:

#ifndef RECT_H 
#define RECT_H
struct Rect { ... }; // code omitted for brevity
#endif // RECT_H

When the preprocessor meets the header for the first time, RECT_H is not defined and everything between #ifndef and #endif will be processed accordingly, including the RECT_H definition. The second time the preprocessor includes the same header file in the same source file, it will omit the contents because RECT_H has already been defined.  

These include-guards are part of directives that control the compilation of parts of the source file. All of the conditional compilation directives are #if#ifdef#ifndef#else#elif, and #endif.

Conditional compilation is useful in many cases; one of them is logging function calls in so-called debug mode. Before releasing the program, it is advised to debug your program and test against logical flaws. You might want to see what happens in the code after invoking a certain function, for example:

void foo() {
log("foo() called");
// do some useful job
}
void start() {
log("start() called");
foo();
// do some useful job
}

Each function calls the log() function, which is implemented as follows:

void log(const std::string& msg) {
#if DEBUG
std::cout << msg << std::endl;
#endif
}

The log() function will print the msg if DEBUG is defined. If you compile the project enabling DEBUG (using compiler flags, such as -D in g++), then the log() function will print the string passed to it; otherwise, it will do nothing.

主站蜘蛛池模板: 台东市| 湖北省| 梅州市| 安福县| 滦平县| 婺源县| 天门市| 楚雄市| 三穗县| 乾安县| 来安县| 松滋市| 临桂县| 平阴县| 微博| 英超| 阿鲁科尔沁旗| 岳池县| 兴义市| 枣阳市| 桦川县| 庄河市| 甘肃省| 岑溪市| 沁源县| 鸡泽县| 新津县| 大丰市| 陇南市| 林西县| 青海省| 双流县| 瓦房店市| 洛川县| 仙居县| 越西县| 尚志市| 陆良县| 精河县| 邹平县| 南投市|