一、什么是多文件编程
为了方便项目的开发与后期维护,最好将同一业务方向的代码放在同一源文件中,这就必然使得项目由分散在不同路径下的多个源文件组成。但涉及到不同源文件定义的变量,数据类型和函数相互引用时会导致一系列的问题,具体的介绍见下文。
C++代码文件根据后缀名不同,大致可以分为以下几类:
.h:头文件
.hpp:头文件,header plus plus的缩写,混杂着.h的声明.cpp的定义,OpenCV采用
.cpp:源文件,Windows
.cc:源文件,Unix/Linux
二、如何防止头文件被重复引用
1、使用宏定义避免
#ifndef _NAME_H_
#define _NAME_H_
/*
* 头文件内容
*/
#endif
_NAME_H_是头文件的名称,需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。
2、使用#pragma once避免
pragma [p'ræɡmə] 编译指示;显示编译指示;特殊指令
使用#pragma once指令,将其附加到指定头文件的最开头出,则该头文件只会被包含一次。
#ifndef是通过定义独一无二的宏来避免重复引用的,这意味着每次引入头文件时都要进行识别,所以效率不高。但考虑到C/C++都支持宏定义,所以项目中使用#ifndef规避可能出现的“头文件重复引用”问题,不会影响项目的可移植性。
#pragma once只能作用于某个具体的文件,而无法像#ifndef那样作用于指定的一段代码。
#pragma once
/*
* 头文件内容
*/
3、使用 _Pragma操作符
_Pragma操作符可以看作是#pragma的增强版,不仅可以实现#pragma所有的功能,还能和宏搭配使用,这里仅介绍用_Pragma操作符避免头文件重复引用。
_Pragma("once")
/*
* 头文件内容
*/
在某些场景中,考虑到编程效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引用,具体方法如下:
#pragma once
#ifndef _NAME_H_
/*
* 头文件内容
*/
#endif
当编译器可以识别#pragma once时,则整个文件仅被编译一次;反之,即便编译器不识别#pragma once指令,此时仍有#ifndef指令发挥作用。
三、include <> 和 #include ""的区别
1、#include <>
#include <>引用的是编译器的类库路径里面的头文件。
假如编译器自带的头文件在/usr/include/下面,则#include <stdio.h>引用的就是/usr/include/stdio.h这个头文件,不管项目在什么目录下面,/usr/include/stdio.h这个路径是确定的,一般用于引用标准头文件,如stdio.h,string.h等。
2、#include ""
#include ""引用的是项目相对路径中的头文件
假如项目的目录为~/C++/my_project,则#include "my.h"引用的是~/C++/my_project下面的my.h这个头文件,一般用于引用自定义的头文件。如果使用#include "",首先会在当前项目所在文件夹下寻找是否有对应的头文件,如果没有,还是会到编译器自带头文件目录中查找。
例如,使用#include "stdio.h",如果项目中不包含stdio.h这个头文件,则还是会定位到/usr/include/stdio.h这个文件。
四、不同路径下的头文件包含(Unix/Linux)
1、头文件位于当前目录
C++\MY_PROJECT
main.cpp
net.cpp
net.h
引用方法:
#include "net.h"
2、头文件位于子目录
C++\MY_PROJECT
│ main.cpp
│ net.cpp
│
└─inc
net.h
引用方法:
#include "inc/net.h"
3、头文件位于父目录
C++\MY_PROJECT
├─inc
│ net.h
│
└─src
main.cpp
net.cpp
引用方法:
#include "../inc/net.h"