iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >解析C++多文件编程问题
  • 875
分享到

解析C++多文件编程问题

2024-04-02 19:04:59 875人浏览 安东尼
摘要

目录一、多文件编程是什么二、如何防治头文件被重复引入1. 使用宏定义避免2. 使用 #pragma once 避免3. 使用 _Pragma 操作符三、命名空间如何应用在多文件编程中

一、多文件编程是什么

为了方便后期的维护,分散代码应遵循一个基本原则:实现相同功能的代码应存储在一个文件中。

c++ 代码文件根据后缀名的不同,大致可以分为如下几类:

.h:头文件
.hpp:头文件,header plus plus 的缩写,混杂着 .h 的声明 .cpp 的定义,OpenCV 采用
.cpp:源文件,windows
.cc:源文件,Unix/linux

对于一些系统提供的库,出于版权和保密考虑,大多是已经编译好的二进制文件,可能仅包含 .h 文件。


// student.h
class Student{
    // ...
};
// student.cc
#include "sudent.h"
// Student 定义
// main.cc
#include "student.h"

int main(){
    // ...
}

二、如何防治头文件被重复引入

1. 使用宏定义避免


#ifndef _NAME_H
#define _NAME_H

//头文件内容

#endif

_NAME_H 是宏的名称。需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。


// student.h
#ifndef _STUDENT_H
#define _STUDENT_H
class Student{
    // ...
};
#endif

2. 使用 #pragma once 避免

使用 #pragma one 指令,将其附加到指定文件的最开头位置,则该文件就只会被 #include 一次。

#ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以 效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。

#pragma once 不涉及宏定义,当编译器遇到它时会立刻知道当前文件只引入一次,所以效率很高。但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好。

#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。


#pragma once
class Student{
    // ...
};

3. 使用 _Pragma 操作符

_Pragma 操作符可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,还能和宏搭配使用。

这里仅介绍用 _Pragma 操作符避免头文件重复引入。

当处理头文件重复引入问题时,可以将如下语句添加到相应文件的开头:

_Pragma("once")


_Pragma("once");
class Student{
    // ...
};

在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被 重复引入。比如说:


#pragma once
#ifndef _STUDENT_H
#define _STUDENT_H
class Student{
    // ...
};
#endif

当编译器可以识别 #pragma once 时,则整个文件仅被编译一次;反之,即便编译器不识别 #pragma once 指令,此时仍有 #ifndef 在发挥作用。

三、命名空间如何应用在多文件编程中

当进行多文件编程时,命名空间常位于 .h 头文件中。


// student_li.h
#ifndef _STUDENT_LI_H
#define _STUDENT_LI_H
namespace Li{
    class Student{
        // ...
    };
}
#endif
// student_li.cc
#include "student_li.h"
#include <iOStream>
void Li::Student::display(){

}
// student_han.h
#ifndef _STUDENT_HAN_H
#define _STUDENT_HAN_H
namespace Han{
    class Student{
        // ...
    };
}
#endif
// student_han.cpp
#include "student_han.h"
#include <iostream>
void Han::Student::display(){}

注意,当类的声明位于指定的命名空间中时,如果要在类的外部实现其成员方法,需同时注明所在命名空间名 和类名(例如本项目中的 Li::Student::display() )。

四、const常量如何在多文件编程中使用

用 const 修饰的变量必须在定义的同时进行初始化操作(除非用 extern 修饰)

C++ 中 const 关键字的功能有 2 个,除了表明其修饰的变量为常量外,还将所修饰变量的可见范围 限制为当前文件。这意味着,除非 const 常量的定义和 main 主函数位于同一个 .cpp 文件,否则该 const 常量只能在其所在的 .cpp 文件中使用。

那么,如何定义 const 常量,才能在其他文件中使用呢?

1. 将 const 常量定义在 .h 头文件中


// demo.h
#ifndef _DEMO_H
#define _DEMO_H
const int num = 10;
#endif
// main.cc
#include <iostream>
#include "demo.h"
int main(){
    std::cout << num << std::endl;
    return 0;
}

2. 借助 extern 先声明再定义 const 常量

借助 extern 关键字,const 常量的定义也可以遵循“声明在 .h 文件,定义在 .cpp 文件”。


// demo.h
#ifndef _DEMO_H
#define _DEMO_H
extern const int num;   // 声明 const 常量
#endif
// demo.cc
#include "demo.h"
const int num = 10;
// main.cpp
#include <iostream>
#include "demo.h"
int main(){
    std::cout << num << std::endl;
    return 0;
}

3. 借助 extern 直接定义 const 常量

C++ 编译器在运行项目时,会在预处理阶段直接将 #include 引入的头文件替换成该头文件中的内容(复制粘贴),因此可以对上节代码做修改:


// demo.cpp
extern const int num = 10;
// main.cpp
#include <iostream>
extern const int num;
int main(){
    std::cout << num << std::endl;
    return 0;
}

五、多文件项目如何用 g++ 命令执行

在 Linux 平台上,虽然也有很多可用的 C++ IDE,但执行 C++ 程序更常采用的方式是使用 g++ 命令。

除此之外,Linux 平台还经常编写 makefile 来运行规模较大的 C++ 项目。

C++ 程序的执行过程分为 4 步,依次是预处理、编译、 汇编和链接。在执行 C++ 项目时,头文件是不需要经历以上这 4 个阶段的,只有项目中的所有源文件才必须经历这 4 个阶段。

假设有这个一个 C++ 项目


// studetn.h
class Student{
    // ...
};
// student.cc
#include <iostream>
#include "student.h"
void Student::say(){
    std::cout << name << "的年龄是" << age << ",成绩是" << score << std::endl;
}
// main.cc
#include "student.h"
int main(){
    Student *pStu = new Student;
    // ...
    delete pStu;
    return 0;
}

预处理阶段,执行如下命令:

[root@boGon ~]# g++ -E main.cc -o main.i
[root@bogon ~]# g++ -E student.cc -o student.i

  • -E 选项用于限定 g++ 编译器只进行预处理而不进行后续的 3 个阶段;
  • -o 选项用于指定生成文件的名称。

编译阶段,进一步生成响应的汇编代码文件:

[root@bogon ~]# g++ -S main.i -o main.s
[root@bogon ~]# g++ -S student.i -o student.s

  • -S 选项用于限定 g++ 编译器对指定文件进行编译,得到的汇编代码文件通常以“.s”作为后缀名。

将汇编文件转换成可执行的机器命令:

[root@bogon ~]# g++ -c main.s -o main.o
[root@bogon ~]# g++ -c student.s -o student.o

  • 如果不用 -o 指定可执行文件的名称,默认情况下会生成 a.out 可执行文件。Linux 系统并不以文件的扩 展名开分区文件类型,所以 a.out 和 student.exe 都是可执行文件,只是文件名称有区别罢了。

最终执行:

[root@bogon ~]# ./student.exe

从头开始直接生成可执行文件:

[root@bogon ~]# g++ main.cpp student.cpp -o student.exe

六、多文件编程的底层原理

实际上,在编译阶段,编辑器会对源文件生成一个符号表,源文件中看不到的定义的符号就会存在这个表中。在链接阶段,编译器会在别的目标文件中寻找这个符号的定义,如何没有找到,会出现链接错误。

定义,指的是就是将某个符号完整的描述清楚,它是变量还是函数,变量类型以及变量值是多少,函数的参数有哪些以及返回值是什么等等;而“声明”的作用仅是告诉编译器该符号的存在,至于该符号的具体的含义,只有等链接的时候才能知道。

C++ 中一个符号允许被声明多次,但只能被定义一次。

基于声明和定义的不同,才有了多文件编程的出现。

所谓的头文件,其实它的内容跟 .cpp 文件中的内容是一样的,都是 C++ 的源代码,唯一的区别在于头文件不 用被编译。我们把所有的函数声明全部放进一个头文件中,当某一个 .cpp 源文件需要时,可以通过 #include 宏命令直接将头文件中的所有内容引入到 .cpp 文件中。这样,当 .cpp 文件被编译之前(也就是预处理阶段),使用 #include 引入的 .h 文件就会替换成该文件中的所有声明。

通常一个头文件的内容会被引入到多个不同的源文件中,并且都会被编译,所以头文件中一般只存放变量或者函数的声明,不要放定义。但存在3种情况属于定义范畴,但应该放在 .h 文件种:

  • 头文件中定义 const 对象、static 对象头文件中定义内联函数,编译器必须在编译时就找到内联函数的完成定义头文件中可以定义类。
  • 类的内部通常包含成员变量和成员函数,成员变量是要等到具体的对象被创建时才会被定义(分配空间),但成员函数却是需要在一开始就被定义的,这也就是类的实现。
  • 通常的做法是将类的定义放在头文件中,而把成员函数的实现代码放在一个 .cpp 文件中。也可以直接实现在类内,作为内联函数。

到此这篇关于C++多文件编程的文章就介绍到这了,更多相关C++多文件编程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 解析C++多文件编程问题

本文链接: https://www.lsjlt.com/news/155547.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解析C++多文件编程问题
    目录一、多文件编程是什么二、如何防治头文件被重复引入1. 使用宏定义避免2. 使用 #pragma once 避免3. 使用 _Pragma 操作符三、命名空间如何应用在多文件编程中...
    99+
    2022-11-12
  • C语言多文件编程问题解析
    目录1 为什么要使用多文件编程2 多文件编程的使用方法3 多文件编程的练习1 为什么要使用多文件编程 在大型的综合项目中,是由很多具有不同的功能的代码构成,不可能将所有的代码都写到一...
    99+
    2022-12-27
    C语言多文件编程 C语言编程
  • C++在vscode中的多文件编程问题解读
    目录C++在vscode中的多文件编程vscode编译多个C++文件问题解决方法总结C++在vscode中的多文件编程 相信有很多的小伙伴在一开始的时候,都会对vscode的多文件编...
    99+
    2023-01-06
    C++ vscode 多文件编程 vscode多文件编程
  • C++多线程编程中的并发问题解析
    C++多线程编程中的并发问题解析随着计算机硬件的不断发展,多核处理器已经成为了主流。在这种情况下,使用多线程来充分利用多核处理器的性能,成为了程序开发中的一项重要技术。然而,在多线程编程中,由于多个线程之间的并发操作,常常会导致一些问题,这...
    99+
    2023-10-22
    解析 并发问题 C++多线程编程
  • 解析C/C++ Capstone 引擎源码编译问题
    Capstone 是一个轻量级的多平台、多架构的反汇编框架。Capstone 旨在成为安全社区中二进制分析和反汇编的终极反汇编引擎。Capstone的编译非常简单只需要一步即可轻松得...
    99+
    2022-11-13
  • C++中文件操作问题分析与解决方案
    C++中文件操作问题分析与解决方案在C++编程中,文件操作是一个非常常见的需求。然而,由于各种原因,可能会出现一些问题。本文将分析几种常见的文件操作问题,并提供相应的解决方案,同时附有具体的代码示例。问题一:文件打开失败当我们尝试打开一个文...
    99+
    2023-10-22
    解决方案 文件操作 问题分析
  • C++多线程编程之如何解决多线程数据共享问题
    这篇文章主要讲解了“C++多线程编程之如何解决多线程数据共享问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++多线程编程之如何解决多线程数据共享问题”吧!通过容器创建多个线程#incl...
    99+
    2023-06-15
  • C语言多文件编写详解
    目录关于多文件调用关于多文件调用中的BUGexternBUG1:ifndef 与 endif总结关于多文件调用 只能有一个 main.c 文件 其余函数分别在 func1.c **...
    99+
    2022-11-12
  • C++中常见的多重继承问题解析
    C++中常见的多重继承问题解析多重继承是一种常见的面向对象编程技术,允许一个类继承多个基类。然而,多重继承也常常引发一些问题和挑战,需要开发人员仔细理解和处理。菱形继承问题菱形继承是指一个派生类同时继承了两个基类,并且这两个基类又共同继承同...
    99+
    2023-10-22
    C++ 多重继承 问题解析
  • VScode中C++头文件问题的终极解决方法详析
    目录引言局部配置全局配置傻傻分不清楚一些有帮助的信息总结引言 之前在配置VScode环境的时候,按照网上的文章配置,总是找不到头文件,搜索解决方案,都是千篇一律,没有说到重点。在此详...
    99+
    2022-11-13
    vscode头文件报错 vscode头文件 vscode开发c语言
  • C++中常见的编码规范问题解析
    C++中常见的编码规范问题解析在进行C++开发过程中,遵循一定的编码规范是非常重要的。良好的编码规范可以提高代码的可读性、可维护性和可扩展性,有助于团队合作和项目的成功实施。然而,在实际的开发中,我们常常会遇到一些常见的编码规范问题。本文将...
    99+
    2023-10-22
    命名规范 缩进问题 注释风格
  • C#编程报错System.InvalidOperationException问题及解决
    目录C#报错System.InvalidOperationException问题场景问题原因解决方案c# WPF InvalidOperationException异常的几种常见原因...
    99+
    2022-11-13
  • 如何解决C# txt文件乱码问题
    本篇内容主要讲解“如何解决C# txt文件乱码问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何解决C# txt文件乱码问题”吧!C#和Java一样,C#提供的类库能够轻松实现对文件的操作。...
    99+
    2023-06-18
  • C++中的多线程同步问题详解
    C++中的多线程同步问题详解在并发编程中,多线程同步是一个重要的问题。当多个线程同时访问共享资源时,会引发各种问题,如竞态条件(Race Condition)、死锁(Deadlock)和活锁(Livock),这些问题都会导致程序的不确定性和...
    99+
    2023-10-22
    C++ 多线程 同步问题
  • 解决Java中properties文件编码问题
    目录1、properties文件显示乱码问题2、读取properties文件乱码3、Spring boot的@ConfigurationProperties读取properties文...
    99+
    2022-11-13
  • 简单解决Python文件中文编码问题
    读写中文 需要读取utf-8编码的中文文件,先利用sublime text软件将它改成无DOM的编码,然后用以下代码: with codecs.open(note_path, 'r+','utf-8')...
    99+
    2022-06-04
    中文 简单 文件
  • 分析和解决golang文件乱码问题
    作为一门新兴的编程语言,Golang在近几年的快速发展中不断吸引着越来越多的程序员。然而,在使用Golang编写文件时,可能会遇到文件乱码的问题,这给程序员的开发带来了很多麻烦。本文将从以下方面对Golang文件乱码问题进行深入探讨。一、G...
    99+
    2023-05-14
  • 怎么解析IE8文件兼容性问题
    怎么解析IE8文件兼容性问题,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。IE8的样式兼容性适应方法IE8文件兼容性用于定义让IE如何编译...
    99+
    2022-10-19
  • 如何解析IE8文件兼容性问题
    这篇文章将为大家详细讲解有关如何解析IE8文件兼容性问题,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。向大家描述一下IE8样式兼容性适应方法,为了帮助确保你...
    99+
    2022-10-19
  • C语言详细分析讲解多文件的程序设计
    目录一、多文件与编译器链接二、多文件之间的相互访问三、关于#include四、头文件使用的一些原则五、再论全局变量六、注意事项七、实验程序八、小结一、多文件与编译器链接 如下图所示,...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作