前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈C++ - 实践之路

漫谈C++ - 实践之路

原创
作者头像
何其不顾四月天
发布2023-12-19 00:30:43
1750
发布2023-12-19 00:30:43
举报
文章被收录于专栏:四月天的专栏四月天的专栏

漫谈C++ - 实践之路

前言

从开始学习C++聊起吧,大学的专业是电子信息工程,从大一开始接触C++,最开始的时候,照着书敲,都会有一大堆错误,也就是熟悉的 烫烫烫烫,再后来接触嵌入式,然后到正式工作,也就正式开始C++的开始旅程。开发的IDE从Vs StudioQt,到notpad++,再到 vs code,也一直在边工作边看书,慢慢的经验在累积也学到的越来越多了。工作到现在大概也有7年了,也应证了那句话,了解的越多也越觉得自己浅薄。也趁着这次的活动记得机会,简单的说一下自己对C++的理解以及使用。

工作嘛,也要从项目整体工程化说起,从需求分析技术选型架构设计软件设计软件开发测试,随后迭代,在实际的生产中应该注意什么,或者使用什么都是一些经验之谈了。

下边也从需求的设计来讲起了。

需求分析

需求理论上来说是有一个需求分析工程师的或者需求从PM下发到我们到手上的需求,我们拿过来怎么理解就是关键了。其实也和项目的大小有关系了,比如说一个项目或者说一个产品的知识单纯的C++服务或者桌面客户端这些需求就会比较少,因为功能单一或者说场景单一。现在一些比较大的项目,通常是web,java,sql,ui,c++都是有的,项目通常比较庞大。需求的拆解或者说需求的边界应该怎么管理,某一个功能模块是由谁来实现,java直接实现或者说web直接实现都是看自己对业务模块的理解或者说功能模块的理解。通常意义上大家都是尽可能让自己的功能单一,业务量减少,这时候去讨论需求分析,就看你对项目的理解和沟通的能力,才会让你尽可能的减少手头的工作量。

需求分析中通常还有一个最初的工时预估,我通常的预估就是实际工作量*2,因为需要考虑到可能难点或者需求的变动这些都要添加考虑进去,尽可能的给自己留下比较充裕的开发时间,给自己后期减少一些加班。

通常意义上,到C++开发人员的需求,大致会有功能指标性能指标两类,优先度通常是功能完成然后性能调试。一些基础的要求运行环境(linux/windows以及系统的发行版本)在开发之初就很明了了,这块的压力会相对小一些。

技术选型

如何选型

在实际的开发的技术选型中,比如说桌面客户端,对于UI就需要看是否有直接的要求了,比如说指定了Qt或者MFC,那其实自己需要参与的选型工作量就会小一点。比如说选择了 Qt,那线程池模型,以及容器模型,还有网络模型日志模型的选择都是自己需要考虑的点,这时候你就需要对各种通用的库就要有一些基本的了解了或者说优缺点。

对于C++来说

代码语言:shell
复制
#线程管理 boost,stl,poco
#容器模型 stl,boost
#网络模型 poco,stl,boost
#事件模型 qt-信号/槽,caf(c++ actor frame)
#日志模型 glog,spdlog,qlog
#序列化 protobuf,json,yaml,xml

这些基础库的选型基本依赖自己的依赖了,但是有一些个人的见解,选择轻量满足业务需求稳定开发量少通用性高

对于业务方向的需求也有一个大致脉络,比如:

代码语言:text
复制
1.虚拟化云桌面 spice,rdp
2.虚拟化 qemu,libvirt,docker,k&s
3.音视频 ffmpeg,gstreamer,opencv,opengl
4.ui 如果需要跨平台-qt,windows-mfc,linux-x11,qt,gtk等
5.嵌入式驱动事件 - v4l2,usbevent,libevent等

这些基础的技术选型,对于一个项目的开发说基本来说技术框架已经搭建好。

可行性验证

基础库的选择可以忽略不考虑,看个人选择了,但是对于业务方向的技术选型,就需要来论证可行性了。初期的技术调研技术验证就需要自己来作了,原则是在做调研或者demo验证的时候尽量充分与全面,业务方向的技术选型的可行性验证基本决定自己项目的成败了。

架构设计

架构设计对于任何语言来说着开发者来说架构的设计是一个软件的基石了,软件六性架构的设计上体现的最为明显,架构的设计决定了软件的稳定性,可扩张性,稳定性,健壮性了。

在我实际的开发中,基本还是使用的最为简洁的MVC了,这样架构的层级比较简洁,业务与基础技术剥离也比较明显。

软件开发

软件开发其实就是这篇文章的主要部分了,需求分析技术选型架构设计基本所有的语言都会涉及到,只是针对的偏重不太一样了,到了软件开发就是到具体语言的落地了。

软件开发其实涉及到了包管理编译链工具依赖库管理代码编写代码测试打包自动化部署等一些流程与步骤。

包管理

类似于dpkg,apt,yum,rmp工具等都是类似于包管理工具,不过是系统的软件包管理,对于语言来说python的pip等类似的工具属于语言的包管理工具。包管理的工具的好处无需赘述,使得开发成本变低,但是对于C++来说,包管理工具就比较难弄了,一直为人所诟病的,在语言设计之初,可能还没有这类的思想或者架构的缺陷,相对而言越新的语言包管理工具功能设计越好,使用感也越好。后来C++也诞生了类似的包管理工具- conan.

对于windows开发,对应的包管理工具是 vcpkg,对应linux相关的开发大多还是使用 conan,其实两个都可以互相使用,但是对应系统的优势还是很明显的。

在使用conan时,其实要注意conanfile的编写以及语法,以及不同库之间的相互依赖调用关系。在这边文章中有一个简单的使用:libudev+V4L2 linux usb摄像头列表发现以及热拔插事件

编译链工具

编译链工具,通俗的来讲就是项目使用什么工具来构建编译脚本,在linux下就是 gun系列就是所有入门的人或者使用的人逃不过的一个工具链。而在windows下通常就是 msvc了。我通常都是面向linux开发,对linux下的多说一些。

在linux下以关连性来介绍了,g++,makefile,autotools,cmake,qmake,其中g++是最底层的工具命令,向上生长为makefile,最上层的就是 autotools,cmake,qmake除了这三个了还有ninja等其他相关的。

备注:这些工具只做简单的介绍,并不做详细的讲解。

g++

最基础的 gcc/g++,有对应的命令行。最初的hello.cpp,就是使用

代码语言:shell
复制
g++ hello.cpp -o hello

其中这是对g++的介绍了:

代码语言:shell
复制
DESKTOP-KT6JB47:~$ g++ --help
Usage: g++ [options] file...
Options:
  -pass-exit-codes         Exit with highest error code from a phase.
  --help                   Display this information.
  --target-help            Display target specific command line options.
  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...].
                           Display specific types of command line options.
  (Use '-v --help' to display command line options of sub-processes).
  --version                Display compiler version information.
  -dumpspecs               Display all of the built in spec strings.
  -dumpversion             Display the version of the compiler.
  -dumpmachine             Display the compiler's target processor.
  -print-search-dirs       Display the directories in the compiler's search path.
  -print-libgcc-file-name  Display the name of the compiler's companion library.
  -print-file-name=<lib>   Display the full path to library <lib>.
  -print-prog-name=<prog>  Display the full path to compiler component <prog>.
  -print-multiarch         Display the target's normalized GNU triplet, used as
                           a component in the library path.
  -print-multi-directory   Display the root directory for versions of libgcc.
  -print-multi-lib         Display the mapping between command line options and
                           multiple library search directories.
  -print-multi-os-directory Display the relative path to OS libraries.
  -print-sysroot           Display the target libraries directory.
  -print-sysroot-headers-suffix Display the sysroot suffix used to find headers.
  -Wa,<options>            Pass comma-separated <options> on to the assembler.
  -Wp,<options>            Pass comma-separated <options> on to the preprocessor.
  -Wl,<options>            Pass comma-separated <options> on to the linker.
  -Xassembler <arg>        Pass <arg> on to the assembler.
  -Xpreprocessor <arg>     Pass <arg> on to the preprocessor.
  -Xlinker <arg>           Pass <arg> on to the linker.
  -save-temps              Do not delete intermediate files.
  -save-temps=<arg>        Do not delete intermediate files.
  -no-canonical-prefixes   Do not canonicalize paths when building relative
                           prefixes to other gcc components.
  -pipe                    Use pipes rather than intermediate files.
  -time                    Time the execution of each subprocess.
  -specs=<file>            Override built-in specs with the contents of <file>.
  -std=<standard>          Assume that the input sources are for <standard>.
  --sysroot=<directory>    Use <directory> as the root directory for headers
                           and libraries.
  -B <directory>           Add <directory> to the compiler's search paths.
  -v                       Display the programs invoked by the compiler.
  -###                     Like -v but options quoted and commands not executed.
  -E                       Preprocess only; do not compile, assemble or link.
  -S                       Compile only; do not assemble or link.
  -c                       Compile and assemble, but do not link.
  -o <file>                Place the output into <file>.
  -pie                     Create a position independent executable.
  -shared                  Create a shared library.
  -x <language>            Specify the language of the following input files.
                           Permissible languages include: c c++ assembler none
                           'none' means revert to the default behavior of
                           guessing the language based on the file's extension.

Options starting with -g, -f, -m, -O, -W, or --param are automatically
 passed on to the various sub-processes invoked by g++.  In order to pass
 other options on to these processes the -W<letter> options must be used.

For bug reporting instructions, please see:
<file:///usr/share/doc/gcc-7/README.Bugs>.

而随后的语法级提升是 Makefile,这时候的编译命令是

代码语言:shell
复制
make -j{cpu-n}

makefile的一些学习地址: 如何学习写makefile?或者随便搜索基本也能找出很多。可以理解为 g++ 的 语法集。

在之后继续升级有两个方向了 autotools 或者cmakelist

autotools

直白的翻译:自动工具链,这时候对复杂工程的或者说大型工程的使用已经基本满足了。

Autotoolsautoscanaclocalautoheaderautomakeautoconf等工具组成,提供了一整套的流程来时满足用户使用。

这是博主的一篇文章关于autotools的使用以及一些简单的理解:Autotools -- 自动编译链工程构建

cmake

官网:cmake

看一下官方的介绍:

代码语言:text
复制
CMake官方版是一款构建、测试和打包软件的跨平台编程工具。CMake官方版是用于控制软件使用简单的平台和编译器编译过程独立配置文件。CMake生成本机makefile和工作区,可以使用用户所选择的编译器环境。

在最近新建的开源项目或者跨平台的C++项目中通常都是使用 cmake来做项目的编译使用了,并且现在 qtcreator也支持cmake了。

基础的编译命令如下了:

代码语言:shell
复制
cmake .. ${options}
make -j{ncpu}
make install
qmake

故名思意:qt的编译链工具了,也有自己的一套独有的语法了,而且 cmake以及qmake也可以互相转换了,都是跨平台工具了。

这是一篇简单介绍工程转换的博文: QMake 工程 转换为CMake 工程

还有qmake语法的介绍博文:Qt-qmake install相关

其他

在windows下MSVC也是类似,不过通常集成在 vsstudio中.qt在windows下支持 mingw还有msvc,同时cmake也是类似。

依赖库管理

依赖库的管理可以使用gitlabgithubconanlocalfile等几种方式。

代码语言:text
复制
github:有在实际构建中依赖网络,有可能因为网络原因或者库的消失导致构建失败,通常不提倡使用github。
gitlab:本地库管理,不过要注意库版本的管理。
# github,gitlab 通常要搭配的 git submodule 来使用,在做版本管理的时候要注意更新以及submit。
conan:包管理工具
localfile:将源码到本地,通常万无一失唯一可能导致源码包过大。

注意:

依赖库管理,通常要注意版本管理,以及在跨平台的时候要注意依赖库的包是否可使用或者支持编译通过

通常依赖库管理要搭配 build-scrite来做编译,在系统构建的时候要注意,conan因为有conanfile.py,可以兼容其他集中类型,或者第一次编译通过后不用再次编译,节省自动构建时间,通常越大的项目越方便。

代码编写

代码编写其实注意事项来来回回就几个,简洁性可读性规范性可扩张,类之间 高内聚,低耦合,以及方法功能的单一性,这些注意事项的规避。

在编写代码的时候,C++的三大特性,多态继承封装就是基石了,通常大家也是围绕着着三大特性来写,不过要特别注意不要写成C,虽然C++完全兼容C。其他的24种设计模式根据需要来使用就可以,并不是强制。在网上大家通常的看到google代码规范一个方法不要超过20行方法的功能尽量单一通常是为同事之间的配合,保证代码的简洁性来提出的这些言论或者方法。

特别注意:C++是面向对象,对象是什么大家的解释通常有很多,个人见解,类即对象。但是经常听到抽象,抽象为什么又是什么呢?就是提取共性,然后功能分层,接口分层,在逻辑上将对象或者接口统一化。在抽象为对象,是将某一个行为过程抽象为对象,提取对应的方法,这就是我理解的面向对象。

其他的就不做介绍了,一些常用的注意事项,基础的语法,C++11/14/17/20/23的特性就不做说明了。

代码测试

这里针对的代码测试通常是说的代码自测(sometesting),在初版的代码开发中,代码的自测通常会很全面以及自己的单元测试,或者功能测试模块的编写,通常会比较详细。在迭代过程中的代码自测,就要包括上一版本基础功能的测试,以防在提交代码后,让测试的同事打回重写,都减少对方的工作量。在这其中要注意的是 一个issue可以作为一个commit,让其他的同事有一个更直观的感受。

自己的测试也通常会包含一些debug,比如说内存测试,cpu测试,dump调试,这时候就要配合各种命令工具的使用了 ptask,backstrace,gdb,valgrind等的使用了。详细的介绍就需要自己一一搜索了。

打包

打包通常是一个项目最后收尾,你要保证你的包要在各种环境下要稳定的运行,所以打包也比较考验一个人的经验,什么是系统底层包,不需要打包进去,又在什么情况下需要所有的打包进去,以及运行脚本的编写,文件目录等都需要考虑到,也是一个相对繁琐的工具了。

打包即生成对应的安装包.

自动化部署

通常都是使用jenkins,其实不是很准确在linux系统或者windows系统下使用Jenkins没有什么问题,但在嵌入式的环境下,尤其封装到设备盒子,更考验部署的周密性,怎么保证系统的纯净性,怎么快速的部署都在考虑到,虽然通常这些都是由运维人员来操作,但是作为开发人员一定要亲手走一遍流程,清楚你的软件是怎么编译,怎么部署,怎么安装,以及碰到了什么问题。

附言

作为一名程序员,一定不要只关注开发的部分,要关注全局,代码编写只是工作的一部分,要了解业务,项目的前因后果,以及项目的部署使用情况,才会让你在开始的时候更加的游刃有余。技术的调研一定要尽心尽力,这是在位自己节省工作,给自己减少坑,在构建项目的时候,项目的文件结构,技术选型,以及代码的编译,部署,打包全流程都要考虑到,才是一个合格的程序员。

想起一句玩笑话,谁敢说自己c++精通呢?

祝大家职业生涯愉快,c++之路顺利。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 漫谈C++ - 实践之路
    • 前言
      • 需求分析
        • 技术选型
          • 如何选型
          • 可行性验证
        • 架构设计
          • 软件开发
            • 包管理
            • 编译链工具
            • 依赖库管理
            • 代码编写
            • 代码测试
            • 打包
            • 自动化部署
          • 附言
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
          http://www.vxiaotou.com