头文件很有用,很多函数都需要一个位置来共用声明(不是定义,定义只能定义一次)。
工程中有两个cpp文件
main.cpp
#include<iostream> void Log(const char* message) { std::cout<<message<<std::endl; } int main() { Log("Hello world!"); std::cin.get(); }
Log.cpp
void InitLog() { Log("Initializing Log"); }
ctrl+F7编译main.cpp不会出错,但是编译Log.cpp会报错,因为Log函数不存在,所以Log.cpp需要什么东西才不会报错,应该怎样告诉他Log函数存在只是在别的文件中?这就需要用到函数声明。因此加上声明编译就不再报错。
void Log(const char* message); void InitLog() { Log("Initializing Log"); }
如果我创立了其他的cpp文件,又要用到Log函数,那么我需要将Log函数的声明再次复制粘贴到其他的cpp文件中。将声明放进头文件中可以简化这个操作,因为include本质就是将头文件的内容直接粘贴到include的位置上。
Log.h
#pragma once void Log(const char* message);
Log.cpp
#include"Log.h"
void InitLog() { Log("Initializing Log"); }
main.cpp不变,将Log.h include进来也没什么问题。如果我想在main.cpp中调用InitLog函数,那么我需要声明他,同样可以将声明加入到头文件中
Log.h
#pragma once void Log(const char* message); void InitLog();
Log.cpp
#include<iostream> #include"Log.h" void InitLog() { Log("Initializing Log"); } void Log(const char* message) { std::cout<<message<<std::endl; }
main.cpp
#include<iostream> #include"Log.h" int main() { InitLog(); Log("Hello world!"); std::cin.get(); }
#pragma once是什么意思
首先以"#"开头是预处理命令,pragma once的意思时这个文件只include一次,被称为头文件保护符,防止我们将一个头文件多次include到一个cpp文件中。
Log.h
//#pragma once void Log(const char* message); void InitLog(); struct player{};
将#pragma once注释掉,然后在Log.cpp中include Log.h两次
#include<iostream> #include"Log.h" #include"Log.h" void InitLog() { Log("Initializing Log"); } void Log(const char* message) { std::cout<<message<<std::endl; }
编译时会发现struct player被重定义,报错。
如果建立一个新的头文件common.h来对其他头文件进行统一引用
#pragma once #include"Log.h"
然后将Log.h中的#pragma once注释掉
这个时候如果在Log.cpp中同时include Log.h和common.h,仍或出现struct player被重定义的错误,因为缺少#pragma once,Log.h被引用两次,导致struct player被重定义。如果取消注释#pragma once,那么会顺利编译,因为#pragma once保证了Log.h只被include一次。另外一种头文件保护是用#ifndef
#ifndef _LOG_H #define _LOG_H void Log(const char* message); void InitLog(); struct player{}; #endif
他要做的时先检查Log h这个符号是否存在,如果没有定义,以下代码将会加入到include中,如果定义了那么这些都不会被include,全部被禁用。最简单的办法是将上面的代码直接复制到cpp文件中
#include<iostream> #include"Common.h" #include"Log.h" #ifndef _LOG_H #define _LOG_H void Log(const char* message); void InitLog(); struct player{}; #endif void InitLog() { Log("Initializing Log"); } void Log(const char* message) { std::cout<<message<<std::endl; }
如果将Common.h和Log.h全部注释掉,代码也不会出错,因为没有检测到log h就将这些定义进去。这种头文件保护符在过去更长荣,现在有了#pragma once后大多使用#pragma once