RoadMap7:C++构建代码库(命名空间与头文件)

摘要:在编写一个项目工程时,显然你大可把所有的代码都写在一个main函数里面,但是这对后续的修改和维护、代码功能的理解会造成很大的不便。构建代码库(Structuring Codebase)是围绕着软件工程处理 如何清晰地实现代码组织如何实现功能模块化 需求提出的处理方法。围绕着这个需求,本章内容将着重讲解如何通过 命名空间头文件 的方法进行代码组织。

1. 命名空间(NameSpaces)

1.1 作用域(Scope)

命名空间本质上就是一种特殊的作用域。因此,在了解命名空间前必须要知道什么是作用域。作用域这个概念在介绍变量的生命周期的时候已经引入,相信对作用域都有模糊的概念,但是并没有做详细的定义。

作用域:指C++程序中变量、函数、类和其他标识符的可见性和可访问性。它决定了这些标识符的寿命和范围。 通常包括:局部作用域、全局作用域、命名空间和类作用域。

局部作用域:被定义在 函数 或者 代码块{ } 内部的变量具有局部作用域。它们无法被外界访问。当然他们的生命周期也仅限于这个函数内部或者带模块内。

全局作用域:相对地,被定义在 函数 或者 代码块{ } 外部的变量具有全局作用域。它们可以在任意位置被访问。当然他们的生命周期也伴随着整个程序的执行。

#include<iostream>// 全局变量
int globalVar = 10;void localExapmle(){int localVar = 99;std::cout << "local Var: " << localVar << std::endl;    // 输出:local Var: 99std::cout << "global Var: " << globalVar << std::endl;  // 输出:global Var: 10
}int main(){localExapmle();// std::cout << "local Var: " << localVar << std::endl; 会报错,显示变量未定义std::cout << "global Var: " << globalVar << std::endl;    // 输出:global Var: 10
}

1.2 命名空间

命名空间本质上就是一种介于全局作用域和局部作用域的特殊的作用域。被使用 命名空间关键字 namespace:

#include<iostream>
// 命名空间的定义
namespace NameofNamespace{int namespaceVar = 5;
}int main(){// 通过命名空间操作符 :: 访问命名空间内部变量std::cout << NameofNamespace::namespaceVar << std::endl;   //输出:5
}

定义在 代码块{ } 内部的变量 (e.g. namespaceVar) 具有命名空间作用域。它们无法被外界访问,但是可通过命名空间操作符::进行访问。当然他们的生命周期也伴随着整个程序的执行。

细心的同学已经发现 std::cout 本质上也是一种命名空间,在很多代码中以下代码段:

#include<iostream>
using namespace std;
namespace NameofNamespace{int namespaceVar = 5;
}
int main(){// 通过 using namespace std 指定整个文件的命名空间都默认为 std,因此使用cout和endl都不需要在前面加入命名空间;cout << NameofNamespace::namespaceVar << endl;   //输出:5
}

通过 using namespace std 指定整个文件的命名空间都默认为 std,因此使用cout和endl都不需要在前面加入命名空间;当然,也可使用关键字 using namespace 指定整个文件的命名空间都默认为自定义的命名空间,如:NameofNamespace 或者同时指定多个命名空间。

#include<iostream>
// 自定义命名空间
namespace NameofNamespace{int namespaceVar = 5;
}using namespace NameofNamespace; // 使用命名空间需要在自定义命名空间之后
using namespace std;  // 同时定义多个命名空间int main(){// 已经指定整个文件的命名空间,因此使用namespaceVar,cout和endl都不需要在前面加入命名空间;cout << namespaceVar << endl;   //输出:5
}

当然,命名空间也支持嵌套,通过 外层命名空间::内层命名空间::变量名 来访问,如:

#include<iostream>
using namespace std;  // 同时定义多个命名空间// 自定义命名空间
namespace Outer{        //外层命名空间namespace Inner{    //内层命名空间int innerVar = 66;}int outerVar = 5;
}int main(){cout << "outerVar: " << Outer::outerVar << endl;   //输出:outerVar: 5cout << "innerVar: " << Outer::Inner::innerVar << endl;   //输出:innerVar: 66
}

1.3 类作用域

上一节我们讲解了通过命名空间操作符 :: 可以访问命名空间内部变量,但应该不少人在类的使用时也见过其他类似的操作符,如 ->. ,他们和命名空间操作符 :: 有什么关系或者差异呢?

操作符 :: 可以结合类名称用于访问类中定义的的静态变量或者用于定义类中已经声明的函数,该运算符把类名视为一种特殊的命名空间

操作符 . 用于访问对象的成员,相比较于操作符 :: ,操作符 . 的操作内容是类实例化的对象(如例子中的obj,而非类MyClass);

操作符 -> 用于访问对象的成员,相比较于操作符 :: ,操作符 -> 的操作内容是类实例化的指针对象(如例子中的obj1,而非类MyClass);

#include <iostream>class MyClass {
public:static int staticMember;int nonStaticMember;void printer();MyClass(int value) : nonStaticMember(value) {}
};int MyClass::staticMember = 7;
// int MyClass::nonStaticMember = 7;  报错,非静态变量不能在类的外部定义;
void MyClass::printer(){std::cout << "I am function! " << std::endl;};int main() {MyClass obj(10);MyClass* obj1;std::cout << "Static member with ::: " << MyClass::staticMember << std::endl;std::cout << "Static member with .: " << obj.staticMember << std::endl;std::cout << "Static member with ->: " << obj1->staticMember << std::endl;std::cout << "Non-static member: " << obj.nonStaticMember << std::endl;
}// Output:
// Static member with namespace: 7
// Static member with .: 7
// Static member with ->: 7
// Non-static member: 10

2. 头文件

头文件,或者说头文件-源文件的代码构建方式是另外一种常见的优化代码结构方法。有利于提高功能模块化、代码可读性和提高维护效率。

  1. 头文件(.h或.hpp)

头文件通常扩展名为.h或.hpp,负责声明多个源文件所需的类、函数和变量。它们充当代码不同部分之间的接口,使管理依赖关系和快速了解代码功能变得更容易,并减少重复代码。

// example.h
#ifndef EXAMPLE_H
#define EXAMPLE_Hclass Example {
public:void printMessage();
};#endif
  1. 源文件(.cpp)

扩展名为.cpp的源文件负责实现相应头文件中定义的实际功能。它们包括所需的头文件,并提供函数和类方法定义。

// example.cpp
#include "example.h"
#include <iostream>void Example::printMessage() {std::cout << "Hello, code splitting!" << std::endl;
}
  1. 分离编译

显然,把功能函数/类写在独立的cpp中,与main函数分离,功能模块化效果大大提升,也更容易理解代码的功能。而分离编译可以有效地提高代码的维护效率。

因为main函数所在的文件和功能cpp文件独立存在,当修改功能时仅仅需要修改cpp文件。因此分离编译的功能就是把main.cpp和功能cpp文件独立编译为不同的对象文件(.o文件),然后再通过连接对象文件,构建最后的可执行文件(.exe文件)。这意味着当只修改某个功能cpp文件时,只需要重新生成它所对应的对象文件(.o文件),而其他文件不需要重新编译,这将大幅度提升编译效率。

# Compile each source file into an object file
g++ -c main.cpp -o main.o
g++ -c example.cpp -o example.o# Link object files together to create the executable
g++ main.o example.o -o my_program

3. 总结

构建代码库(Structuring Codebase)是围绕着软件工程处理 如何清晰地实现代码组织如何实现功能模块化 需求提出的处理方法。围绕着这个需求,本章内容将着重讲解如何通过 命名空间头文件 的方法进行代码组织。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/593453.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 if...elif...else 语句判断数字是

以下实例通过使用 if...elif...else 语句判断数字是正数、负数或零&#xff1a; 实例(Python 3.0) # Filename : test.py # author by : www.dida100.com # 用户输入数字 num float(input("输入一个数字: ")) if num > 0: print("正数") eli…

WEB:探索开源OFD.js技术应用

1、简述 OFD.js 是一个由开源社区维护的 JavaScript 库&#xff0c;专注于在浏览器中渲染和处理 OFD 文件。OFD 作为一种开放式的文档格式&#xff0c;被广泛应用于电子政务、电子合同等领域。OFD.js 的出现为开发者提供了一个强大的工具&#xff0c;使得在前端实现 OFD 文件的…

Docker仓库搭建与镜像推送拉取

1.Docker镜像仓库 搭建镜像仓库可以基于Docker官方提供的DockerRegistry来实现。 官网地址&#xff1a;https://hub.docker.com/_/registry 1.1.简化版镜像仓库 Docker官方的Docker Registry是一个基础版本的Docker镜像仓库&#xff0c;具备仓库管理的完整功能&#xff0c;…

【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88682033 目录 【Matlab】BP 神经网络时序预测算法 【Matlab】CNN卷积神经网络时序预测算法 【Matlab】ELM极限学习机时序预测算法 【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测 【Mat…

【力扣100】【好题】79.单词搜索

添加链接描述 class Solution(object):# 定义上下左右四个行走方向directs [(0, 1), (0, -1), (1, 0), (-1, 0)]def exist(self, board, word):""":type board: List[List[str]]:type word: str:rtype: bool"""m len(board)if m 0:return Fa…

机器学习-实践:海量文件遍历和简单计算器实现

今日我们分享2个机器学习的实践代码海量文件遍历和简单计算器实现。 海量文件遍历 In [40] !tree -L 3 ./data/ ./data/ ├── data19638 │ ├── insects │ │ └── insects │ └── insects.zip └── data55217├── Zebra│ ├── others│ └─…

Docker安装Flarum(开源论坛)

Flarum介绍安装命令 #---------------------------------------------------------- mkdir -p /opt/flarum && cd /opt/flarum #---------------------------------------------------------- docker run -p 8888:8888 --name flarum \ --restartalways \ -v /opt/flar…

2 Windows网络编程

1 基础概念 1.1 socket概念 Socket 的原意是“插座”&#xff0c;在计算机通信领域&#xff0c;socket 被翻译为“套接字”&#xff0c;它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层&#xff0c;它是一组用于网络通信的API&#xff0c;包括了一系列…

resetlogs失败故障恢复-ORA-01555---惜分飞

客户数据库resetlogs报错 Tue Dec 19 15:21:23 2023 ALTER DATABASE MOUNT Successful mount of redo thread 1, with mount id 1683789043 Database mounted in Exclusive Mode Lost write protection disabled Completed: ALTER DATABASE MOUNT Tue Dec 19 15:22:01 2023…

scss使用for循环遍历,动态赋值类名并配置不同颜色

需求&#xff1a;后端要传入不同的等级&#xff0c;前端通过等级展示不同的字体颜色&#xff0c;通过scss遍历更有利于动态修改颜色或者增删等级 1.通过 for $i from 1 through 4 定义循环&#xff0c;索引值为i 2.nth($colors, $i) 取出对应的颜色 $colors: #ff0000, #00ff…

Vivado JESD204B与AD9162建立通信实战总结

一、FPGA与AD9162的JESD204B接口 FPGA作为JESD204B接口的发送端&#xff0c;AD9162作为JESD204B接口的接收端。FPGA和AD9162的device clk、SYSREF由同源时钟芯片产生。其中&#xff0c;FPGA和AD9162的divice clk时钟不同&#xff0c;并且FPGA的decive clk等同于JESD204B IP的co…

RK3568驱动指南|第九篇 设备模型-第100章 在总线目录下创建属性文件实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

qiankun微服务

官网 &#x1f4e6; 基于 single-spa 封装&#xff0c;提供了更加开箱即用的 API。 &#x1f4f1; 技术栈无关&#xff0c;任意技术栈的应用均可 使用/接入&#xff0c;不论是 React/Vue/Angular/JQuery 还是其他等框架。 &#x1f4aa; HTML Entry 接入方式&#xff0c;让你接…

如何利用ChatGPT处理文本、论文写作、AI绘图、文献查阅、PPT编辑、编程等

无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&#xff0c;提高编程效率和准确性。此外&#xff0c;ChatGPT是一位出色的合作伙伴&#xff0c;可以为您提供论文写作的支持。它可以为您提供论文结构指导、段落重组建议…

低代码技术:颠覆数据孤岛的技术利器

在当今数据驱动的世界中&#xff0c;数据的价值无可忽视。然而&#xff0c;很多组织面临一个普遍的问题&#xff0c;即数据孤岛。数据孤岛指的是不同部门或系统之间无法有效共享和集成数据的情况。这限制了组织在数据驱动的决策和创新方面的能力。然而&#xff0c;低代码平台的…

关于HarmonyOs的参数传递UI刷新以及List,Grid嵌套数据传递,ui刷新问题总结

最近在学习开发过程中遇见一系列的参数传递以及ui刷新问题&#xff0c;在这里做个总结分享。 以下是在开发过程中遇见的问题&#xff1a; 1.页面与子组件之间的参数传递与UI刷新 2.Builder自定义内部子组件的参数传递与UI刷新 3.Grid与List item发生变化Ui刷新问题 4.List…

uniapp条件判断,在各平台执行不同代码等详解

文章目录 1️⃣ 条件判断1.1 方法支持1.2 写法1.3 js文件写法1.4 vue文件写法1.5 css文件写法1.6 平台名称详解优质资源分享作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/135260505 uniapp条件判断,在各平台执行不同代码等详解,uniapp代码…

keil如何查看flash和ram占用情况

Keil MDK编译器下查看占用Flash和SRAM空间大小_keil sdram 1k-CSDN博客 1、如何查看各函数占用内存大小&#xff1a; keil查看使用的内存还剩多少_keil如何查看空间-CSDN博客

陈述式资源管理(2)

命令行。声明式资源管理 三种常见的项目发布方式&#xff1a; 1、蓝绿发布 2、金丝雀发布&#xff08;灰度发布&#xff09; 3、滚动发布 应用程序升级&#xff0c;最大困难就是新旧业务之间的切换。立项 --- 定稿 --- 需求发布 --- 开发 --- 测试 --- 发布。测试之后上线…

docker搭建Dinky —— 筑梦之路

简介 Dinky 是一个 开箱即用 、易扩展 &#xff0c;以 Apache Flink 为基础&#xff0c;连接 OLAP 和 数据湖 等众多框架的 一站式 实时计算平台&#xff0c;致力于 流批一体 和 湖仓一体 的探索与实践。 主要功能 其主要功能如下&#xff1a; 沉浸式 FlinkSQL 数据开发&#x…