0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C++代码需要遵循的10个最佳实践

CPP开发者 来源:DeepNoMind 作者:俞凡 2022-10-18 15:20 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

C++代码提供了足够的灵活性,因此对于大部分工程师来说都很难把握。本文介绍了写好C++代码需要遵循的10个最佳实践,并在最后提供了一个工具可以帮助我们分析C++代码的健壮度。

1. 尽可能尝试使用新的C++标准

到2022年,C++已经走过了40多个年头。新的C++标准实际上简化了许多令人沮丧的细节,提供了新的现代方法来改进C++代码,但让开发人员认识到这一点并不容易。

以内存管理为例,这可能是C++中受到最多批评的机制。多年来,对象分配都是由new关键字完成的,开发人员一定得记住在代码的某个地方调用delete。“现代C++”解决了这个问题,并促进了共享指针的使用。

2. 使用命名空间模块化代码

现代C++库广泛使用命名空间来模块化代码库,它们利用“Namespace-by-feature”方法,按功能划分命名空间来反映功能集,将单个特性(且仅与该特性)相关的所有内容放到单个命名空间中。从而使得命名空间具有高内聚性和高模块化,并且耦合最小,紧耦合的项目被放在了一起。

Boost是按特性分组的最佳示例,其包含数千个命名空间,每个命名空间用于对特定的特性进行分组。

3. 抽象

数据抽象是C++中面向对象编程最基本和最重要的特性之一。抽象意味着只显示基本信息而隐藏细节,数据抽象指的是仅向外部世界提供关于数据的基本信息,隐藏背景细节或实现。

尽管许多书籍、网络资源、会议演讲者和专家都推荐这种最佳实践,但在很多项目中,这条规则仍然被忽略了,许多类的细节并没有被隐藏。

4. 类越小越好

具有多行代码的类型应该被划分为一组较小的类型。

需要很大的耐心重构一个大的类,甚至可能需要从头重新创建所有东西。以下是一些重构建议:

BigClass中的逻辑必须被分成更小的类。这些较小的类最终可能成为嵌套在原始God Class中的私有类,God Class的实例对象由较小嵌套类的实例组成。

较小的类划分应该由God Class负责的多个职责驱动。要确定这些职责,通常需要查找与字段的子集强耦合的方法的子集。

如果BigClass包含的逻辑比状态多,一个好的选择是定义一个或几个不包含静态字段而只包含纯静态方法的静态类。纯静态方法是一种只根据输入参数计算结果的函数,它不读取或分配任何静态或实例字段。纯静态方法的主要优点是易于测试。

首先尝试维护BigClass的接口,并委托调用新提取的类。最后,BigClass应该是一个没有自己逻辑的纯接口,可以为了方便将其保留,也可以将其扔掉,并开始只使用新类。

单元测试可以提供帮助: 在提取方法之前为每个方法编写测试,以确保不会破坏功能。

5. 每个类尽量提供最少的方法

包含20个以上方法的类可能很难理解和维护。

一个类有许多方法可能是实现了太多责任的症状。

也许所面对的类控制了系统中太多的其他类,并且已经超出了应有的逻辑,成为了一个无所不能的类。

6. 加强低耦合

低耦合是理想状态,可以在应用中进行较少的更改实现程序的某个变更。从长远来看,可以减少修改、添加新特性的大量时间、精力和成本。

低耦合可以通过使用抽象类或泛型类和方法来实现。

7. 加强高内聚

单一责任原则规定一个类不应该有多于一个更改的理由,这样的类被称为内聚类。较高的LCOM值通常可以意味着类的内聚性较差。有几个LCOM指标,取值范围为[0-1]。LCOM HS (HS代表Henderson-Sellers)取值范围为[0-2]。LCOM HS值大于1时需要产生警惕。下面是计算LCOM指标:

LCOM = 1 — (sum(MF)/M*F)
LCOM HS = (M — sum(MF)/F)(M-1)

其中……

M是类中方法的数量(包括静态方法和实例方法,它还包括构造函数、属性getter/setter、事件添加/删除方法)。

F是类中实例字段的数量。

MF是类访问特定实例字段的方法数量。

Sum(MF)是该类所有实例字段的MF之和。

这些公式背后的基本思想可以表述如下: 如果一个类的所有方法都使用它的所有实例字段,那么这个类就是完全内聚的,这意味着sum(MF)=M*F,然后LCOM = 0和LCOMHS = 0。

LCOMHS值大于1就需要警惕了。

8. 只注释代码不能表达的内容

鹦鹉学舌的代码注释没有为读者提供任何额外的东西。代码库中充斥着嘈杂的注释和不正确的注释,促使程序员忽略所有的注释,或者采取积极的措施隐藏它们。

9. 尽量不要用重复的代码

众所周知,重复代码的存在对软件开发和维护有负面影响。实际上,一个主要缺点是,当为了修复bug或添加新特性而更改重复代码的实例时,所有对应的代码必须同时更改。

产生重复代码最常见的原因是复制/粘贴操作,这种情况下,相似的源代码出现在两个或多个地方。许多文章、书籍和网站都警告不要采用这种做法,但有时实践这些建议并不容易,开发人员还是会选择简单的解决方案: 复制/粘贴大法。

使用适当的工具可以容易的从复制/粘贴操作中检测到重复代码,但是,在某些情况下,克隆代码很难被检测到。

10. 不变性有助于多线程编程

基本上,如果对象在创建之后状态不变,那么这个对象就是不可变(immutable)的。如果一个类的实例是不可变的,那么该类就是不可变的。

不可变对象极大简化了并发编程,这是支持使用它的重要理由。想想看,为什么编写适当的多线程程序是一项艰巨的任务?因为同步线程访问资源(对象或其他操作系统资源)是很困难的。为什么同步这些访问很困难?因为很难保证多个线程对多个对象进行的多次写访问和读访问之间不会出现竞争条件。如果不再有写访问会怎么样?换句话说,如果被线程访问的对象的状态没有改变会怎么样?就不再需要同步了!

关于不可变类的另一个好处是它们永远不会违反里氏替换原则(LSP, Liskov Subtitution Principle),以下是维基百科对LSP的定义:

Liskov的行为子类型的概念定义了可变对象可替换性的概念,也就是说,如果S是T的子类型,那么程序中T类型的对象可以被替换为S类型的对象,而不改变该程序的任何期望属性(例如,正确性)。

如果没有公共字段,没有可以更改其内部数据的方法,并且派生类方法无法更改其内部数据,那么引用对象类就是不可变的。因为值不可变,所以在所有情况下都可以引用相同的对象,不需要复制构造函数或赋值操作符。出于这个原因,建议将复制构造函数和赋值操作符设为私有,或者从boost::noncopyable继承,或者使用新的C++ 11特性“显式默认和删除特殊成员函数”[2]。

如何加强对这些最佳实践进行检查?

CppDepend[3]提供了名为CQLinq[4]的代码查询语言,可以像数据库一样查询代码库。开发人员、设计人员和架构师可以自定义查询,以便轻松找到容易出现bug的情况。

通过CQLinq,可以结合来自代码度量、依赖关系、API使用和其他模型的数据来定义非常高级的查询,以匹配容易出现bug的情况。

例如,分析clang源代码后,可以检测到大类:

873f83c0-4e99-11ed-a3b6-dac502259ad0.png

检测到有大量方法的类:

876b6bac-4e99-11ed-a3b6-dac502259ad0.png

或者检测到内聚性较差的类:

8802c402-4e99-11ed-a3b6-dac502259ad0.png

审核编辑:郭婷


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    22

    文章

    2122

    浏览量

    76694
  • 代码
    +关注

    关注

    30

    文章

    4940

    浏览量

    73116
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    C++程序异常的处理机制

    运行代码进行分离,使得程序更加模块化;另一方面,C++的异常处理可以不需要异常处理在异常发生时的同一函数,而是可以在更上层合适的位置进行处理。 下面,我们一起来看看
    发表于 12-02 07:12

    嵌入式C/C++回归测试四大最佳实践(附自动化测试工具TESSY使用教程)

    嵌入式开发中,一次微小的代码改动都可能引发“蝴蝶效应”,如何守护系统的稳健?推荐专业的自动化测试工具#TESSY,源自戴姆勒-奔驰,是嵌入式C/C++单元/集成测试的标杆。
    的头像 发表于 10-31 14:21 182次阅读
    嵌入式<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>回归测试四大<b class='flag-5'>最佳</b><b class='flag-5'>实践</b>(附自动化测试工具TESSY使用教程)

    C/C++代码静态测试工具Perforce QAC 2025.3的新特性

     Perforce Validate 中 QAC 项目的相对/根路径的支持。C++ 分析也得到了增强,增加了用于检测 C++ 并发问题的新检查,并改进了实体名称和实
    的头像 发表于 10-13 18:11 330次阅读
    <b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>代码</b>静态测试工具Perforce QAC 2025.3的新特性

    Perforce QAC产品简介:面向C/C++的静态代码分析工具(已通过SO 26262认证)

    Perforce QAC专为C/C++开发者打造,支持多种编码规范、功能安全标准(ISO 26262)等,广泛用于汽车、医疗、嵌入式开发领域,可帮助快速识别关键缺陷、提升代码质量、实现合规交付。
    的头像 发表于 07-10 15:57 823次阅读
    Perforce QAC产品简介:面向<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>的静态<b class='flag-5'>代码</b>分析工具(已通过SO 26262认证)

    Linux网络管理的关键技术和最佳实践

    在大型互联网企业中,Linux网络管理是运维工程师的核心技能之一。面对海量服务器、复杂网络拓扑、高并发流量,运维人员需要掌握从基础网络配置到高级网络优化的全套技术栈。本文将结合大厂实际场景,深入解析Linux网络管理的关键技术和最佳实践
    的头像 发表于 07-09 09:53 670次阅读

    在OpenVINO™ C++代码中启用 AddressSanitizer 时的内存泄漏怎么解决?

    在 OpenVINO™ C++代码中启用 AddressSanitizer 时遇到内存泄漏: \"#0 0xaaaab8558370 in operator new(unsigned
    发表于 06-23 07:16

    天马荣获新财富杂志“2024 ESG最佳实践奖”

    天马可持续发展•ESG表现再获认可,上榜2024年新财富杂志最佳上市公司评选“ESG最佳实践榜单”。
    的头像 发表于 05-21 14:43 718次阅读

    创建了用于OpenVINO™推理的自定义C++和Python代码,从C++代码中获得的结果与Python代码不同是为什么?

    创建了用于OpenVINO™推理的自定义 C++ 和 Python* 代码。 在两推理过程中使用相同的图像和模型。 从 C++ 代码
    发表于 03-06 06:22

    DLP4500怎么确定投影仪开始投影的同时相机的c++代码开始运行?

    投影仪通过trig1 链接相机,投影仪投图同时触发相机,相机采集图像并传回电脑,相机的代码需要添加dlp4500的api或sdk代码吗,怎么确定投影仪开始投影的同时相机的c++
    发表于 02-18 07:16

    BEM+Sass结合使用的最佳实践

    BEM(Block Element Modifier)与Sass的结合使用是前端开发中一种高效且规范的样式编写方式。以下是一些最佳实践,旨在帮助开发者更好地利用这两种工具来提高代码的可读性、可维护性
    的头像 发表于 02-12 16:50 949次阅读

    代码加密、源代码防泄漏c/c++与git服务器开发环境

    代码加密对于很多研发性单位来说是至关重要的,当然每家企业的业务需求不同所用的开发环境及开发语言也不尽相同,今天主要来讲一下c++及git开发环境的源代码防泄密保护方案。企业源代码泄密
    的头像 发表于 02-12 15:26 862次阅读
    源<b class='flag-5'>代码</b>加密、源<b class='flag-5'>代码</b>防泄漏<b class='flag-5'>c</b>/<b class='flag-5'>c++</b>与git服务器开发环境

    基于OpenHarmony标准系统的C++公共基础类库案例:ThreadPoll

    1、程序简介该程序是基于OpenHarmony标准系统的C++公共基础类库的线程池处理:ThreadPoll。本案例完成如下工作:创建1线程池,设置该线程池内部有1024线程空间。启动5
    的头像 发表于 02-10 18:09 594次阅读
    基于OpenHarmony标准系统的<b class='flag-5'>C++</b>公共基础类库案例:ThreadPoll

    Spire.XLS for C++组件说明

    Spire.XLS for C++ 是一款专业的 C++ Excel 组件,可以用在各种 C++ 框架和应用程序中。Spire.XLS for C++ 提供了一
    的头像 发表于 01-14 09:40 1293次阅读
    Spire.XLS for <b class='flag-5'>C++</b>组件说明

    兆芯最佳实践应用场景解决方案发布

    《兆芯最佳实践应用场景解决方案》现已正式发布,扫描下方二维码或点击阅读原文即可获取下载。
    的头像 发表于 01-13 14:45 841次阅读

    AKI跨语言调用库神助攻C/C++代码迁移至HarmonyOS NEXT

    产品创新与功能迭代,而非技术迁移的细节问题,大幅提升开发效率。 据悉,在涉及C/C++/ETS跨越语言调用的鸿蒙化应用中,有超过80%的项目都在使用AKI,如某知名购物应用,使用后减少了项目10%
    发表于 01-02 17:08