c++程序分文件编写,看这篇就够了

经常听到一个名词——分文件编写

那么,这是什么?
分文件编写(模块化编程)的含义是将一个程序的代码分多个文件存储,也就是将不同的功能模块放在不同的文件中,并在这些模块之间建立必要的联系,通过模块的互相协作完成整个功能的程序设计方法。
在这里插入图片描述

而,它又有什么优点呢?

1.优点

1. 易维护:分文件编写程序可以方便地进行模块化的管理,每个模块都有相对独立的功能和职责,修改其中一个模块不会影响到其他模块的功能,因此程序的维护和更新更加容易。

2. 代码复用:模块化的编程可以使得多个程序共用同一模块,以减少代码的冗余和重复性。

3. 可读性强:分文件编写可以使程序更易读,每个模块的功能和职责清晰明确,易于理解。

4. 提高开发效率:程序员可以同时开发多个模块来实现整个程序,这样可以提高开发效率。

5. 方便测试:模块化的程序可以分别进行测试,这样可以更加方便地识别和解决程序中的问题。

6. 提高程序稳定性:模块化的编程可以减少程序出错的可能性,提高程序的稳定性和可靠性。1. 易维护:分文件编写程序可以方便地进行模块化的管理,每个模块都有相对独立的功能和职责,修改其中一个模块不会影响到其他模块的功能,因此程序的维护和更新更加容易。

1、文件类型

C++程序通常分为三类文件:

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

1.1、头文件

头文件的存在是为了联系多个源文件,它们是源文件之间的接口。与C语言类似,C++要求先声明后使用,但编译时是单文件编译的。下面是一个没有头文件的例子:

// main.cpp
void fun();     // 必须先声明,否则会出错

int main(){
    
    
fun();       // 调用fun函数
}

// fun.cpp
#include <iostream>
void fun(){
    
    
std::cout << "This is fun." << std::endl;
}

通过命令"g++ main.cpp fun.cpp"编译这两个文件后,可以正常运行。需要了解的是,C++的编译过程是将每个文件单独编译,然后通过链接将编译得到的多个文件组合成一个可执行程序。编译时只检查函数声明,只要该文件在之前声明过函数,就能成功编译。函数定义在链接阶段检查,链接是多个文件共同参与的。在上述例子中,main.cpp必须先声明函数fun()才能通过编译,尽管在main.cpp中没有定义该函数,但在链接时发现fun.cpp定义了该函数,因此程序是正确的。

然而,每次使用其他文件的函数都要手动先声明是很繁琐且容易出错的。因此,我们将声明语句放入一个文件中,称之为"头文件"。如果需要使用某个函数,就将其所在的头文件包含进来,头文件的内容会在编译前粘贴到源文件中,这样在编译时就能正常通过。接下来看一个使用了头文件的例子:

// main.cpp
#include "header.h"

int main(){
    
    
fun();
}

// header.h
#ifndef HEADER_H
#define HEADER_H

void fun();

#endif

// fun.cpp
#include <iostream>
void fun(){
    
    
std::cout << "This is fun." << std::endl;
}

头文件的内容通常会使用条件编译预处理语句(如上例)包围起来,以防止由于依赖关系的问题被多次包含。

既然了解了头文件的作用,那么哪些内容应该放在头文件中?哪些不应该放在头文件中?很简单,如果这部分需要复制给每个相关的cpp文件,就将其放在头文件中;如果在多个cpp文件中复制后可能导致链接错误,就不要放在头文件中。具体来看:

函数声明:显然应该放在头文件中,前面已经讲过。
类定义、结构定义:想象下函数定义的逻辑,似乎不能放在头文件中。但实际上应该放在头文件中。首先,每个cpp文件应该有一个定义,编译器才能知道如何为对象分配空间。其次,类型定义不会在内存上分配空间。
模板函数:编译器必须根据函数模板在编译时实例化对应的函数,所以应该放在头文件中。
内联函数:在编译时插入调用位置,因此也应该放在头文件中。
函数定义:不要!C++规定一个程序中同一签名的函数只能有一个定义。如果将函数定义放在头文件中,并且多个cpp文件包含了该头文件,链接时会出现多个定义版本,导致链接错误。
变量定义:不要!与上述情况类似,被多个文件包含时会有多次定义同一个变量的问题,导致链接错误。但是,static变量和extern变量可以在多个文件中出现,以及宏定义的常量,因为这些不会引起链接错误。

1.2、cpp源文件

在将头文件的内容抽离出去后,剩下的内容可以放在cpp文件中。在cpp文件中,除了需要包含对应的头文件之外,没有什么变化。

尽管都是cpp文件,仍然有必要将其视为模块文件和主程序文件。在实际开发中,模块文件和主程序文件的功能提供者和使用者通常由不同的人开发。

2、多文件编译

如果使用Windows下的集成开发环境,只需点击"Build"按钮,一键搞定,但你可能对这个过程的理解会有所欠缺。因此,以Linux为例,介绍最简单的多文件编译命令:

g++ main.cpp fun.cpp -o out # 列举所有要编译的文件

也可以先单独编译为.o文件,然后再链接:

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

第二种方式可能会引起疑惑——为什么这么麻烦?然而,这种方式提供了一个优点——模块编译更新。只需要编译修改过的文件,再与其他文件进行链接,无需重新编译整个项目。

在实际项目中,项目文件数量可能非常多,不管使用哪种方式,都需要逐一列出文件,这并不实际。集成开发环境工具自然没有这个问题。但是在Linux上,也可以使用Makefile来进行项目管理,实现自动编译。当然,这又是另一个需要学习的方面了。

猜你喜欢

转载自blog.csdn.net/aliyonghang/article/details/132548330