当我们想在一个cpp文件中创建函数,然后想在另一个cpp文件中使用,当我们尝试编译那个文件时,编译器不知道那个文件的存在,所以编译会报错。
所以我们需要一个共同的地方来存放声明(注:是函数的声明而非定义,我们只能定义函数一次)
举例
#include<iostream>
void Log(const char* message)
{
std::cout<<message<<std::endl;
}
int main()
{
Log("Hello World!");
std::cin.get();
}
上述例子中,主函数调用了一个函数Log,它的作用是能帮助我们打印信息到控制台。
新建一个源文件Log.cpp写一个新的初始化函数InitLog和原来的打印函数:
#include <iostream>
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
std::cout << message << std::endl;
}
此时编译一下的话肯定会发生错误,因为在这个文件中编译器不认识Log函数,我们并没有对其进行声明。
添加一个Log函数的声明后,我们就可以成功编译运行这个文件了。
#include <iostream>
void Log(const char* message);//声明时别忘记添加分号
void InitLog(const char* message)
{
Log("Initializing Log");
}
void Log(const char* message)
{
std::cout << message << std::endl;
}
到现在为止,我们找到了一个告诉Log.cpp文件那个Log函数位于某处的方法——添加一个函数声明。
但如果我们有多个文件都用到了这个函数,需要在每一个文件中都复制粘贴这个声明吗?
The answer is YES!但有另外一个方法可以让这一切变的简单清爽一点,就是头文件。include预处理指令可以将我们的头文件复制粘贴到每个地方,这正是现在我们需要的。
我们新建一个头文件:右击头文件——添加——新建项——新建头文件.h——命名Log.h
头文件Log.h声明了两个函数InitLog和Log:
#pragma once
void InitLog();
void Log(const char* message);
在main函数里再调用一下InitLog函数,此时编译会报错,因为原main.cpp文件中同样没有这对这两个函数进行声明,所以我们include一下头文件Log.h:
#include <iostream>
#include "Log.h"
int main()
{
InitLog();
Log("Hello World!");
std::cin.get();
}
同样的,在Log.cpp文件中,删去原来对于Log函数的声明void Log(const char* message),添加上头文件Log.h:
#include "Log.h"
#include <iostream>
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
std::cout << message << std::endl;
}
然后在main中运行程序,则程序也可以运行成功。运行结果如图:
头文件中自动生成的#pragma once
我们注意到pragma也是以#开头的,所以它其实也是一个预处理指令,pragma once的意思实际上指的是只include这个文件一次。
所以Pragma once实际上是一种header guard(头文件保护符),它是为了防止我们把单个头文件多次include到一个cpp单元里。
我们如果在一个cpp文件中多次include同一个头文件,编译器会报错!!!比如说我们创建一个struct来举例。
struct是指结构体,是常用的自定义构造类型(常见的数据打包方法),它需要唯一的名字(也就是你定义的结构体的名字不能相同)。
现在我们在Log.h中添加一个struct的定义并且把pragma once注释掉:
//#pragma once
void InitLog();
void Log(const char* message);
struct player{};//里面不添加任何变量,就是一个空的。
然后新建一个common头文件common.h:
#pragma once
#include"Log.h"
回到Log.cpp文件中,假如我们同时include了两个头文件:
#include "Log.h"
#include"common.h"
#include <iostream>
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
std::cout << message << std::endl;
}
编译器会报错,因为struct被重复定义了两次,我们如果回到Log.h把注释掉的pragma once恢复,编译就不会出错,顺利进行了。