前言

这是我的第二篇博客

上篇文章写了很多c++开发游戏所需的函数,可是那么多函数,太麻烦了,我们怎样能简便快速地使用一个函数呢?
这就要引入c++的一个概念:多文件编程。


1 多文件编程

稍微大一点的项目都不会是单个文件的,多文件的好处实在太多,模块开发、分工协作、代码复用、结构清晰、模块更新……

我们先认识一下c++的文件类型:

  1. 头文件(.h):放置各种声明,用于被cpp文件包含。
  2. 模块文件(.cpp):放置一些函数定义,也称为功能模块。
  3. 主程序文件(main.cpp):程序入口,调用模块文件实现的方法。

1.1 头文件

头文件,也叫c++源文件,一般不会编译,如果cpp文件使用了头文件,编译时就会把头文件的内容拷贝到cpp文件中。
平时我们使用的#include<bits/stdc++.h>就是引入头文件的代码。

1.1.1 头文件的组成

//main.h
//预编译语句,防止重复
#ifndef MAIN_H
#define MAIN_H
//引用所需的头文件
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
//一些宏定义
#define ll long long
#define MAXN 10e9
#define INF 0x3f3f3f3f
#define N 501 namespace std{
//这里面的内容都是std命名空间里的
//关于命名空间请看下文
class game{
//定义一个类
public:
//一些函数和定义
void init();
bool gameover();
struct{//类内也可以定义结构体哦
string usename,password;
}use;
};
void game::init(){
//一些内容
}
bool game::gameover(){
//一些内容
}
} #endif//结束头文件

也就是说,我们可以在头文件里写一些工具函数,然后在主函数里使用。
那么,写完的头文件应该存在哪里呢?

1.1.2 头文件的储存

快捷键ctrl+B,可以打开当前文件的所在位置,可以看到,bits/stdc++.h这个头文件的目录是:

好了,让我们研究研究dev-c++的文件组成。

Dev-Cpp目录下,有一堆文件和文件夹,而大部分头文件都存储在MinGW32下。
打开MinGW32,我们可以看到:

其中,每一个文件夹里都有很多的头文件(share目录里主要是和其它语言的交互,例如python),也就是说,我们把头文件存在哪里都行。
不过据观察,dev-c++大部分的头文件都在"Dev-Cpp\MinGW32\lib\gcc\mingw32\9.2.0 "里。
那么有一个疑问,为什么bits/stdc++.h前面要有一个bits/呢?
其实,bits是一个文件夹:

这些文件的位置是:"Dev-Cpp\MinGW32\lib\gcc\mingw32\9.2.0\include\c++\"
这个文件夹里有很多耳熟能详的头文件,比如algorithm,比如如cmath
而这里面的文件夹:bitsext等,里面也有很多的头文件(bits是标准库。ext是拓展库)

我们可以尝试自己建一个文件夹,例如qwq
然后再里面建几个头文件:比如qwq.hqmath.hqcolor.h等。
我们写程序的时候就可以:

#include<qwq/qwq.h>
#include<qwq/qmath.h>
#include<qwq/qcolor.h>

这样还是有点不方便。
我们可以建一个头文件all.h,在里面这么写:

#ifndef ALL_H
#define ALL_H #include<qwq/qwq.h>
#include<qwq/qmath.h>
#include<qwq/qcolor.h> #endif

然后写程序的时候写一行:

#include<qwq/all.h>

就可以了。
多方便啊!

1.2 多文件编程

dev-c++有一个功能就是项目。
选择左上角的文件,然后选择新建,再选择项目。
他会出来一个这样的界面:

我们选择Console Application。名称就叫……qwq

会有一个main.cpp的文件。

#include <iostream>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
return 0;
}

除此之外,还会有这些文件:

然后我们再选择文件/新建/类

会蹦出来qwq.cppqwq.h
ctrl+s保存,然后就会出现代码:

```qwq.h```
#ifndef QWQ_H
#define QWQ_H class qwq{
public:
qwq();
protected:
}; #endif
```qwq.cpp```
#include "qwq.h"
qwq::qwq(){ }

现在qwq目录下是这样的:

我们可以随便写一些代码。如:

```qwq.cpp```
#include "qwq.h"
#include<bits/stdc++.h>
using namespace std;
qwq::qwq(){
cout<<"这是一个头文件qwq!\n";
}

然后再main.cpp下添加这个头文件。

```main.cpp```
#include "qwq.h"
int main(int argc, char** argv) {
qwq();
return 0;
}

效果:

dev-c++会同时编译qwq.cppmain.cpp两个文件:

g++ -c main.cpp -o main.o
g++ -c qwq.cpp -o qwq.o
g++ main.o qwq.o -o out

qwq.h的内容已经被编译器拷贝到qwq.cppmain.cpp中了。

这就是多文件编程


2 命名空间

举个栗子:
记得在一个课外班学习时,班级里有两个叫做张伟的同学,老师不得不想了一个办法,当叫长得高一点的张伟时,就说:高张伟,长得矮的就叫做:矮张伟。

同样的情况也出现在 C++ 中。比如你写一个叫做h()的函数,但当你编译的时候,你惊奇地发现,这个函数竟然已经有了!

因此,引入了命名空间这个概念,专门用于解决上面的问题,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。

实例:

#include<bits/stdc++.h>
namespace qwq{
int a=1;
}
using namespace std;
int main(){
int a=3;
cout<<qwq::a;
return 0;
}

这个程序运行后,会输出1
因为输出的变量a是在命名空间qwq中的,而在主函数中定义的a则是在标准命名空间中的。

那么假如我们换一种代码:

cout<<a;

这回的输出就是3了。

很神奇吧,其实命名空间内可以有很多内容,比如函数、类,甚至嵌套命名空间!

#include<bits/stdc++.h>
namespace qwq{
int a=1;
namespace qwq1{
int a=3;
}
}
using namespace std;
int main(){
cout<<qwq::a<<" "<<qwq::qwq1::a;
return 0;
}

这回的输出是1 3

如果嫌太累,你可以在主函数上面加上一个using namespace qwq;然后就不用再写qwq::a

但是命名空间也不能滥用,下面是一个错误事例:

#include <bits/stdc++.h>
using namespace std;
namespace qwq{
int a = 100;
int orz(){
cout<<"a="<<a<<endl;
}
namespace qwq1{
int a =20;
int orz(){
cout<<"a="<<a<<endl;
}
}
}
using namespace qwq;
using namespace qwq::qwq1;
int main(){
orz();
return 0;
}

这样会出错:会显示 a 变量和 orz函数 “was not declared in this scope”,编译器不知道要去使用哪个 a 和 fun()。
所以要不然就不用using,要不然就之using一个命名空间。


总结

本来是准备写一下自己的头文件的,没想到牵扯出来这么多东西,既然这样,那编写自己的头文件就放在下篇文章吧!
还是感谢引用文章的作者,说实话这篇文章和上篇文章我都是在边学习边写的。

另外,做一些无聊的统计:
本篇文章共5550字,275行,10图片,共花费时间9小时。


引用文章

  1. 我终于把C++多文件编程理解透彻了
  2. 菜鸟编程:C++ 命名空间

c++游戏编程(2)多文件编程与命名空间的更多相关文章

  1. java文件编程总结

    文件编程之一就是文件操作,就是新建,删除,复制,更名 新建文件用createNewFile()方法,要处理IOException异常 新建文件夹用mkdirs()方法 删除一个文件和一个空的文件夹直接 ...

  2. 单片机中用c编程时头文件reg51.h及reg52.h解析

    单片机中用c编程时头文件reg51.h及reg52.h解析 我们在用c语言编程是往往第一行就是reg51.h或者其他的自定义头文件,我们怎么样来理解呢? 1)“文件包含”处理. 程序的第一行是一个“文 ...

  3. 系统调用方式文件编程,王明学learn

    系统调用方式文件编程 一.文件描述符 在Linux系统中,所有打开的文件也对应一个数字,这个数字由系统来分配,我们称之为:文件描述符. 二.函数学习 2.1打开文件  open 2.1.2 函数原形 ...

  4. linux应用程序开发-文件编程-系统调用方式

    在看韦东山视频linux驱动方面有一些吃力,究其原因,虽然接触过linux应用程序编程,但是没有深入去理解,相关函数用法不清楚,正好看到国嵌视频对这一方面讲的比较透彻, 所以把学习过程记录下来,也作为 ...

  5. (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  6. (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  7. extern的使用详解(多文件编程)——C语言

    extern——关键字 extern是C语言中的一个关键字,一般用在变量名前或函数名前,作用是用来说明“此变量/函数是在别处定义的,要在此处引用”,extern这个关键字大部分读者应该是在变量的存储类 ...

  8. 多功能电子通讯录(涉及到了双向链表的使用,Linux文件编程等等)

    readme.txt //作为一个程序员,我们咋么能不写用户手册呢!MSP的我觉得用户体验是王道,苹果手机的用户体验的确不错!不过WP加油!我去,扯远了!赶紧看我的程序吧!  歡迎使用多功能電子通訊錄 ...

  9. linux文件编程----系统调用

    linux中文件编程可以使用两种方法: 1).linux系统调用 2).C语言库函数 前者依赖于linux系统,后者与操作系统是独立的. 在 linux系统中,所有打开的文件也对应一个数字,这个数字由 ...

  10. Android 网络编程--上传文件及相应的参数到服务器

    之前一直在做SiteCheck的项目,所用到的知识大部分都涉及到网络编程方面,所以现在有时间先把它的使用方法及一些注意事项记录下来.在这里我用两种例子让大家了解它的使用方法: (1)上传图片及相应参数 ...

随机推荐

  1. MySQL索引相关知识学习心得

    你知道的越多,你不知道的也就越多 -- 芝诺曾 一.MySQL索引学习 MySQl主要有两种类型的索引:哈希索引.B+树索引 1.哈希索引 哈希索引可以以O(1)的时间复杂度进行查找,但是这样查找导致 ...

  2. GPS地图生成02之经典算法体验

    经典的利用轨迹生成地图的算法与数据集可寻找于:Mapconstruction by pfoser Mapconstruction by pfoser数据集中,雅典数据集投影坐标系为(UTM, GGRS ...

  3. Java语法基础课程总结

    1.运行实例EnumTest.java并分析 结论:枚举类型属于引用类型,不属于原始数据类型它的每一个具体值都引用一个特定的对象,可以使用"=="直接比较枚举变量的值,枚举是可以从 ...

  4. Net Core 网关 Ocelot 简单案例

    1.什么是Ocelot Ocelot是一个用.NET Core实现并且开源的API网关,它功能强大,包括了:路由.请求聚合.服务发现.认证.鉴权.限流熔断.并内置了负载均衡器与Service Fabr ...

  5. LeetCode-2039 网络空闲的时刻

    来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/the-time-when-the-network-becomes-idle 题目描述 给你一个有 ...

  6. Kotlin学习-函数(表达式,lambda,高阶函数)

    Kotlin中函数 3种表达形式: 一般函数: fun sum(a: Int, b: Int): Int { return a+b } 简化函数为表达式形式: fun sum2(a: Int, b: ...

  7. 在github上如何克隆带子模块的项目?

    使用命令git clone --recursive xxxx(项目地址).

  8. Python中文官方文档

    Python 2.7.18 的中文文档:  https://docs.python.org/zh-cn/2.7/ Python 3.10.6 的官方文档:https://docs.python.org ...

  9. rancher 修改域名

    rancher 修改域名 rancher 修改ingress.nginx 对应的域名后 cattle-system 名称空间下的pod 依然是连接旧环境的rancher 域名 解决办法 1. 需要登录 ...

  10. java开发细节

    Java开发细节 Java源文件以.java 为扩展名.源文件的基本组成部分为类(class),如本类中的Hello类 Java应用程序的执行入口是main()方法.它有固定的书写格式: public ...