C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(1)

news/2024/11/7 16:23:43/

        在使用模块之前,头文件用于提供代码重用的接口。头文件确实有许多问题,比如避免同一头文件的多重包含以及确保头文件的包含顺序正确。还有,简单的#include,例如,<iostream>就添加了几千行代码,编译器不得不编译。如果几个源文件#include <iostream>,所有这些翻译单元变得更大了。这还只是包含了一个简单的头文件。想像一下,如果需要<iostream>,<vector>,<format>等等。

        模块解决了所有这些问题,甚至更多。模块被import的顺序并不重要。模块一旦被编译为进制格式,每当该模块被import进行另一个源文件时,编译器就可以使用。这与头文件是一个明显的对比,头文件是每当编译器碰到#include那个头文件时都要进行一而再再而三的编译。因此,模块可以极大节省编译时间。当在模块中修改了内容时,也节省了增加的编译时间,例如,修改一个模块接口文件中的导出函数实现,不需要触发使用那个模块的用户的重新编译。模块不受外部定义宏的影响,任何在模块中定义的宏对模块之外的任何代码不可见,也就是说,模块是自我隔离的。因此,推荐如下:

        注意:有了以上讨论的好处,如果编译器支持模块,新写的代码应该使用模块来结构化代码成为逻辑上分隔的构造块。

        如果可能的话,历史遗留代码也可以慢慢转换为模块。然而,遗留代码太多了,许多第三方库还不支持模块,现在也不是所有的编译器完全支持模块。基于这些原因了解传统的头文件是如何工作的依然重要。这就是本章仍然要包含头文件的讨论的原因。

        注意:如何编译模块与编译器相关。咨询编译器的文档来学习特定编译器的模块工作方式。

        注意:如果你的编译器不支持模块,那就只能将我们的例子转化为非模块的代码了,但还是建议你与时俱进,跟上时代的脚步吧,找一个支持模块的编译器,使你的工作事半功倍;而不是因循守旧,事倍功半。

1、将代码非模块化

        如果想要使用还不完全支持模块的编译器来编译本博客中的代码,可以按如下步骤将代码非模块化:

  • 重命名.cppm模块接口文件为.h头文件。
  • 在每个.h头文件的顶部添加#pragma once。
  • 去除export module xyz声明
  • 替换module xyz声明为#include来包含相应的头文件。
  • 替换import与export import声明为合适的#include指令。如果代码使用了import std;那就需要用#include指令来包含所有需要的单个头文件了。
  • 去除任何export关键字。
  • 去除所有的module;,它指出了全局模块部分的开始。
  • 如果函数定义或变量定义出现在一个.h头文件中,在前面添加inline关键字。

2、标准命名的模块(c++23)

        通过导入标准命名模块std可以访问c++标准库的任何东东。该命名模块使得整个标准库可用,包括所有的定义在<cstddef>中的C功能。然而,只要通过std命名空间就可以使用所有的C功能。对于遗留代码,可以考虑导入std.compat命名模块,它导入了所有的std import的,同时使得std命名空间与全局空间的C功能可用。在新的代码中不推荐使用std.compat。

3、模块接口文件

        模块接口文件定义了由模块提供的功能的接口,通常以.cppm作为文件扩展名。模块接口文件以声明标示文件是由一个特定的名字定义的模块开头。这叫做模块声明。模块名字可以是任何合法的c++标识符。名字可以包含.但是不能以.开始或结束,并且不能一行中包含多个.。合法的名字的例子是datamodel,mycompany.datamodel,mycompany.datamodel.core,datamodel_core,等等。

        注意:目前,还没有模块接口文件的标准扩展名。然而,大多数编译器支持.cppm(C++模块)扩展名,所以我们也这么用。可以检查一下你的编译器使用的是什么样的扩展名。

模块需要显式声明要把什么导出去,也就是说,当客户端代码导入模块时什么是可见的。模块可以导出任何声明,例如变量声明,函数声明,类型声明,using指令,以及using声明。还有,导入声明也可以被导出。从模块中导出实体通过export关键字来完成。从模块中没有导出的东东只在模块自身内可见。所有导出的实体的集合叫做模块接口。

        下面是一个模块接口文件的例子,名字叫做Person.cppm,定义了一个person模块,导出了一个Personal类。注意,它导入了由std提供的功能。

export module person;    // Named module declarationimport std;                // Import declarationexport class Person        // Export declaration
{
public:explicit Person(std::string firstName, std::string lastName): m_firstName{ std::move(firstName) }, m_lastName{ std::move(lastName) } { }const std::string& getFirstName() const { return m_firstName; }const std::string& getLastName() const { return m_lastName; }private:std::string m_firstName;std::string m_lastName;
};

        在标准术语中,所有东东以命名模块声明开始(上面代码段中的第一行),直到文件结尾,叫做模块范围。

        Person类可以通过导入person模块来使用,如下(test.cpp):

import person;
import std;using namespace std;int main()
{Person person{ "Kole", "Webb" };println("{}, {}", person.getLastName(), person.getFirstName());
}

        任何东东都可以从模块导出,只要它有名字。例子为类定义,函数原型,类枚举类型,using声明与指令,命名空间,等等。如果命名空间使用export关键字显式导出,该命名空间中的所有东东也自动导出。例如,下面的代码段导出了整个DataModel命名空间;因此,没有必要再显式导出单个类与类型别名:

export module datamodel;import std;export namespace DataModel
{class Person { /* ... */ };class Address { /* ... */ };using Persons = std::vector<Person>;
}

        也可以使用export block导出一个声明的整块,下面是一个例子:

export
{namespace DataModel{class Person { /* ... */ };class Address { /* ... */ };using Persons = std::vector<Person>;}
}


http://www.ppmy.cn/news/1545114.html

相关文章

30天如何成功转行成为AI产品经理?如果你也想转行到AI,赶紧进来抄作业!!!

前言 随着AI技术的快速发展&#xff0c;AI产品经理成为了备受瞩目的职业。如果您也想抓住这个机遇&#xff0c;不妨跟随这份30天快速入门指南&#xff0c;开始您的AI产品经理转型之旅。 一、学习路线 第一阶段&#xff08;5天&#xff09;&#xff1a;初阶应用 该阶段让大家…

SpringCloudGateway — 网关登录校验

单体架构时我们只需要完成一次用户登录、身份校验&#xff0c;就可以在所有业务中获取到用户信息。而微服务拆分后&#xff0c;每个微服务都独立部署&#xff0c;不再共享数据。也就意味着每个微服务都需要做登录校验&#xff0c;这显然不可取。 1. 思路分析 既然网关是所有微…

微信小程序之流浪动物救助:爱与希望同行

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

ENSP 基于全局地址池的DHCP服务

DHCP(Dynamic Host Configuration Protocol)动态主机配置协议&#xff0c;是一个应用层协议。当我们将客户主机IP地址设置为动态获取方式时&#xff0c;DHCP服务器就会根据DHCP协议给客户端分配IP&#xff0c;使得客户机能够利用这个IP上网。 DHCP前身是BOOTP&#xff0c;在Li…

python的安装环境Miniconda(Conda 命令管理依赖配置)

这一段时间&#xff0c;对AI大模型 有了兴趣就想研究一下。 在研究之前肯定要先把需要的编程技能掌握了。经过我查阅资料&#xff0c;今天就先学一下 python的 环境安装。 Node.js 包管理工具&#xff1a;npm 依赖配置文件&#xff1a;package.json 环境管理&#xff1a;nvm&am…

刘艳兵-DBA027-在Oracle数据库,通常可以使用如下方法来得到目标SQL的执行计划,那么通过下列哪些方法得到的执行计划有可能是不准确的?

在Oracle数据库&#xff0c;通常可以使用如下方法来得到目标SQL的执行计划&#xff0c;那么通过下列哪些方法得到的执行计划有可能是不准确的&#xff1f; A explain plan 命令 B SQLPLUS中的AUTOTRACE开关 C DBMS_XPLAN包 D 10046事件 答&#xff1a; A expla…

为什么要学习 Java 编程

1991 年&#xff0c;Sun Microsystems 创造了历史。 当时的目标是设计一种用于电视机顶盒的编程语言。 James Gosling&#xff08;Java 之父&#xff09;本人可能从未预料到&#xff0c;他即将为 IT 行业的未来奠定基础。 Java 以其简洁易读的代码形式和复杂的面向对象编程语…

重构响应对象

一、基本概念 重构&#xff1a;重构是指在不改变软件外部行为的前提下&#xff0c;对软件内部结构进行调整和优化&#xff0c;以提高代码质量、可读性和可维护性。 响应对象&#xff1a;在软件开发中&#xff0c;响应对象通常指的是服务器对客户端请求所做出的响应内容&#…