C++中的不良设计

行为树基本概念与BehaviorTree.CPP库在C++的代码实现 文章介绍了行为树的基本概念以及介绍了MIT开源的行为树实现库——BehaviorTree.CPP的使用,包含部分C++的代码实现 阅读详情

 

  首先声明,起这么一个标题,目的是为了“耸人听闻”,吸引读者。:) 文中的两个函数的缺陷,不是我所发现,只是我认为很有意义,与大家共享。而且,可以了解一个成熟系统的“缺陷”,不是非常让人愉快和兴奋吗?

  本文的部分内容引用了林锐的《高质量C++/C编程指南》一书。(建议大家都去读读,尤其我找工作的时候,不少小公司直接使用了书中的C++试题作为笔试题目 :) )

1: printf()

相信大家都使用过,MFC 中的TRACE有同样的问题。printf()的缺陷是不安全性和不可扩展性。

1)关于不安全性,《高质量C++/C编程指南》一书有明确的解释:

【建议6-1-2】尽量不要使用类型和数目不确定的参数。

C标准库函数printf是采用不确定参数的典型代表,其原型为:

int printf(const chat *format[, argument]…);

这种风格的函数在编译时丧失了严格的类型安全检查。

int i;

printf("%s",i);  // 编译时无法使用严格的类型安全检查。

 

2)关于不可扩展性,是指它不可以和自定义的类型配合使用。请看以下代码:

int i;

float f;

CStudent student; // 自定义的类型,其中重载了 << 操作符

cout << i << f << student;

printf("%d %f",i,f); // 不能和student配合使用

 

2. getchar()函数,《高质量C++/C编程指南》一书有明确的解释

       1)  【规则6-2-2】函数名字与返回值类型在语义上不可冲突。

违反这条规则的典型代表是C标准库函数getchar。

例如:

char c;

c = getchar();

if (c == EOF)

…

按照getchar名字的意思,将变量c声明为char类型是很自然的事情。但不幸的是getchar的确不是char类型,而是int类型,其原型如下:

        int getchar(void);

由于c是char类型,取值范围是[-128,127],如果宏EOF的值在char的取值范围之外,那么if语句将总是失败,这种“危险”人们一般哪里料得到!导致本例错误的责任并不在用户,是函数getchar误导了使用者。

 

  2) 【规则6-2-3】不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return语句返回。

回顾上例,C标准库函数的设计者为什么要将getchar声明为令人迷糊的int类型呢?他会那么傻吗?

在正常情况下,getchar的确返回单个字符。但如果getchar碰到文件结束标志或发生读错误,它必须返回一个标志EOF。为了区别于正常的字符,只好将EOF定义为负数(通常为负1)。因此函数getchar就成了int类型。

我们在实际工作中,经常会碰到上述令人为难的问题。为了避免出现误解,我们应该将正常值和错误标志分开。即:正常值用输出参数获得,而错误标志用return语句返回。

函数getchar可以改写成 BOOL GetChar(char *c);

虽然gechar比GetChar灵活,例如 putchar(getchar()); 但是如果getchar用错了,它的灵活性又有什么用呢?
【C++】使用 yaml-cpp 库操作 YAML 配置文件有利于我们灵活配置工程,解决大量重复劳动,也方便调试。YAML 是一种人类可读的数据序列化格式,它使用缩进和特定的符号来表示数据结构。在本文中,我们将详细介绍如何在 C++ 中使用yaml-cpp库来解析和生成 YAML 格式的数据。 阅读详情

相关推荐

CPP已老?Herb Sutter开发CPP2,努力证明CPP的强大

这使您可以在任何现有的C++项目和构建系统中开始尝试Cpp2语法,只需将源文件从.cpp重命名为.cpp2并添加一个构建步骤,结果可以在每个C++20或更高版本的编译器和所有现有的C++工具(调试器、构建系统、sanitizer等)中直接使用,而无需进行任何更改。Cpp2旨在成为C++本身的另一种“皮肤”,只是一种更简单、更安全的编写普通C++类型/函数/对象的方式,以及在更简单的编译器和语法风格中尝试未来新标准C++功能的更快方法。例如,它没有自己的非标准不兼容模块/概念等,与标准C++功能竞争;

yuxingwu9872的博客 832

可恶的C语言——代码风格

代码风格 #include指令应置于整个程序最上方。 缩进应使用4个空格或等长的Tab,且应可区分代码内外层的逻辑。 右花括号前不应该有多余空行。 独立意义的代码块应用空行隔开,但不应该有两个连续的空行。 尽量少使用全局变量。且局部变量不应该与上一代码块中变量重名,但可与全局变量重名。 只在一个函数中使用到的需全局空间或生命周期的变量,必须定义为static的局部变量。 空函数可使用不换行的{}。 void类型的函数常规返回应省return。 非void类型的函数不应无默认情况的return。 命名应使用

blll0的博客 262

关于Win11安装Ubuntu子系统报错:WslRegisterDistribution failed with error 解决办法

Win11安装Ubuntu子系统报错:WslRegisterDistribution failed with error

qq_51908382的博客 3万+

所遇不良设计(一)

Table of Contents 1. 扩展的常量 2. 多变的函数 3. 强势的friend 4. 层叠的工程   我们在设计时,一定要考虑系统的未来的可扩展性,为未来做好准备,预备接口。现在软件的设计为了降低其耦合度,大多将软件设计成插件模式。 1 扩展的常量   系统中出现大量的常量,随着系统模块的添加,会不断增加这些常量; ...

dlzptbbs534263的博客 206

AirSim安装和地图加载

详细教程如何安装AirSim并加载地图

fegxg的博客 3034

【华为OD机试】真题-小明减肥(Java)

摘要:题目要求从n个可选运动中选取k个,使其卡路里总和等于目标值t,统计可行方案数。输入包含运动数量n、目标t、选择数量k及卡路里数组。采用DFS回溯算法,通过剪枝优化(提前终止无效分支),分别处理选择/不选当前运动的情况。当遍历完所有运动且满足条件时计数。示例输入"4 3 2"和"1 2 3"时,输出2(对应两种选择组合)。Java实现通过递归完成搜索,最终输出符合条件的方案总数。(149字)

u014481728的博客 287

不良设计的征兆

1.设计的结构很难做改变,或者改变的代价很高2.设计结构中的一处做了改动,就在其他地方产生问题。3.当前的软件不能够重用,或者不存在重用。4.类与类之间的关联度很高,或者软件与环境的关联度很高。5.某些类的职责很集中,出现以该类为中心,辐射很多关联的情况。、6.继承非常多,而很少有组合。7.机能相关的设计,与职能相关的设计混杂在一起。

hugekueng的专栏 593

什么是DHCP Snooping?如何配置DHCP Snooping?

功能描述防护类型防御伪造 DHCP 服务器、避免地址冲突、增强网络安全性使用场景企业园区网、校园网、大型局域网配合机制IP Source Guard、DAI、防止 ARP 欺骗部署难度⭐⭐(简单)“DHCP Snooping,是内网 DHCP 安全防护的第一道门神。” 🛡️。

网络技术联盟站 1267

C++编码风格/规范/建议

Google 开源项目风格指南 里面包含五份(C++ 、Objective-C、Python 、JSON、Shell )中文版的风格指南。

yzhwind的博客 3246

ADS基础教程24 - Gerber文件的导入

一、引言二、基本概念1.仿真文件下载2.仿真文件介绍二、导入步骤1.新建workspace2.选择Layout结构3.导入设计4.选择文件类型5.导入文件6.预览文件内容7.铜皮离散问题四、总结选择。通过本文章结束,可以了解ADS中如何将导入Gerber文件,并且对导入的铜皮进行合并。下一步就针对导入的文件进行层叠设置和编辑。END!}}END!

XZ_ZC的博客 3057

innovus:insert Power Switch失败,报告not covered by a row问题解析

这个问题就是switch找不到可以放置的row,分析就从两方面入手,一方面从voltage area下手,一方面从row和site入手。检查发现voltage area设置正确,row也存在,只不过lef里缺少对应switch的双倍高的site。更多学习内容请关注「拾陆楼」知识星球。

m0_61544122的博客 1159

【C++入门】访问权限管控和继承机制详解

(2)但是在派生类还是可以调用基类的同名成员的,可以使用指定域名的方法:父类::成员;显示的指定要调用父类的成员而不是派生类的成员;

weixin_42031299的博客 2267

ros入门(八)---TF坐标转换

TF(TransForm),就是坐标转换,包括了位置和姿态两个方面的变换。

weixin_51157015的博客 3389

Modern C++ API Design, pt 1

方法重载集合是指在相同的作用域(例如:类、命名空间)内,具有相同名字的多个函数版本。每个版本的参数类型、数量、顺序等可能不同。例如,函数可能和其他的f()函数重载一起,形成一个重载集合。非拥有型重载指的是函数接收非拥有型的引用或指针。通常是接受**const引用**(或指针)、std::string_view和 std::span之类的类型,这些类型并不拥有数据,只是提供对数据的访问。const:确保方法不会修改对象的成员。左值引用 (:适用于左值,通常用于修改对象或返回自身。右值引用 (

虾球 1025

2、硬件工程师笔试面试汇总(2025版本)

本文摘要:文章系统梳理了硬件工程师笔试面试中的电子元器件知识要点,涵盖电阻、电容、电感、二极管、三极管、MOS管等器件的工作原理、选型要点和应用场景。详细解析了UART、I2C、SPI等通信协议的特点及实现方式,并探讨了电源管理、信号处理、PCB设计等核心问题。针对常见电路如放大电路、滤波电路、逻辑电路等提供了深入分析,同时介绍了示波器使用、单片机系统设计等实用技能。文章还包含器件封装、电平转换、时序分析等工程实践内容,并附有相关真题解析和仿真实验指导,为硬件工程师提供全面的技术参考。

XU157303764的博客 9011

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C++ 类的继承

一、为什么C++需要用到“继承” 实不相瞒,我身边有位同学,他姓张,姑且叫他张同学。有一天,张同学哭着跟我说,“我好惨啊,你说上天怎么对我这么不公平,我长着一副英俊潇洒的脸,明明可以考实力闯出一番事业的,偏偏整天被家里逼迫,要我去继承十几亿身家,呜呜呜……”。 虽然我想揍他,但想了想,他还是个小孩,需要他人的关爱。算了,今晚就奉献一点爱给他。 他继承了继承了十几亿能去干嘛? 他可以买十年真题,他可以买遥控车,他可以买棒棒糖,他可以把十几亿转账给我… 说到底,就是使用他老爸的钱来完成某一样事情… 那C++的继

weixin_38956024的博客 775

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Cpp入门基础

定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中 即为命名空间的成员。命名空间中可以定义变量/函数/类型等。namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下 ⾯的rand不在冲突了。C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。

2401_86658278的博客 5194

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C++中的八大设计原则

C++ 中的八大设计原则可以帮助我们创建高内聚、低耦合的代码。

GOLOJO的博客 1909

如何理解C++中的.h文件和.cpp文件

如何理解C++中的.h文件和.cpp文件一、源文件如何根据#include来关联头文件二、头文件如何来关联源文件三、声明与定义的区分:综上所诉   建立一个以类为名字的XX.h文件,声明类,再建立一个相同名字的XX.cpp文件(要#include “XX.h”),实现类中的函数, 在有main 函数的.cpp里声明函数,建一个与函数名一样的.cpp文件,实现该函数;并且要 #include “XX.h” 一、源文件如何根据#include来关联头文件   1.系统自带的头文件用尖括号括起来,这样编译器会在系

weixin_39303983的博客 4035

从零构建C++ AI对话引擎:ChatAI-Cpp深度解析

那天凌晨三点,当我终于让C++程序与AI完成第一次对话时,突然意识到:原来让C++与AI对话可以这么简单。如果你也曾在HTTP请求、JSON解析和编码转换中挣扎,这篇深度解析或许能帮你少走弯路。 ## 当C++遇见AI:一场技术革命 还记得第一次尝试在C++项目中集成OpenAI API时的场景吗?你需要引入curl库处理网络请求,找到合适的JSON解析器,还要处理Windows平台的中文编码

gitblog_00566的博客 860

探索CPP-Reflection:C++中的元编程魔法

在C++的世界里,元编程是一种强大的工具,它允许我们在编译时执行计算和生成代码。`CPP-Reflection`是由Austin Brunkhorst创建的一个开源库,它为C++引入了简单而直观的反射机制,使得开发者可以更容易地探索和操作程序的运行时信息。 ## 项目简介 `CPP-Reflection`是一个轻量级的库,它的核心目标是提供一种方式让C++代码能够自我描述,允许你在运行时检查类

gitblog_00084的博客 1107

反射C++库Reflect-CPP完全指南

--- ## 项目介绍 Reflect-CPP是一个基于C++20的库,它通过编译时反射实现了快速的序列化、反序列化以及验证功能,填补了C++开发中的一项重要空白。此库设计紧密集成C++标准库容器,遵循C++惯用语法,并且开箱即用地支持JSON格式,同时易于扩展到其他如BSON、CBOR、flexbuffers、msgpack、TOML、XML和YAML等序列化格式。Reflect-CPP强调...

gitblog_00062的博客 1555

基于yaml-cpp的C++参数服务器设计

基于yaml-cpp的C++参数服务器设计,实现动态修改C++变量,无需编译,0.04ms

m0_73800387的博客 1152

如何用cpp-dependencies在5分钟内发现C++项目中的循环依赖问题

你是否曾在开发C++项目时遇到难以调试的编译错误?是否发现代码结构逐渐变得混乱,模块间的依赖关系越来越复杂?今天,我将向你介绍一个强大的工具——cpp-dependencies,它能帮助你在短短5分钟内发现C++项目中的循环依赖问题,让你的代码架构更加清晰、健壮。 ## 什么是cpp-dependencies? cpp-dependencies是一个专门用于分析C++项目依赖关系的工具。它能扫

gitblog_01009的博客 572

【C++】特殊类的设计、单例模式以及Cpp类型转换

本文深入探讨C++中特殊类的设计方法与类型转换机制。针对特殊类设计,详细解析如何实现禁止拷贝、限制对象创建于堆/栈、防止继承及单例模式(饿汉与懒汉),并分析其应用场景与线程安全问题。在类型转换部分,系统介绍C++四种强制转换操作符(static_cast、reinterpret_cast、const_cast、dynamic_cast)的原理与适用场景,剖析隐式转换的潜在风险(如数据截断与死循环),并对比C风格转换的缺陷。通过实例代码与场景分析,帮助开发者掌握高效、安全的编程实践,提升代码健壮性与可维护性。

2303_77756141的博客 2236
上一篇: CDialog的派生类中OnOK()函数和virtual的关系
下一篇: 庆祝收到工作的offer,增加几个帖子!
ecai
博客等级 码龄26年 6粉丝 27原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值