变频空调用膨胀阀项目可行性研究报告【申请可修改】.doc
《变频空调用膨胀阀项目可行性研究报告【申请可修改】.doc》由会员分享,可在线阅读,更多相关《变频空调用膨胀阀项目可行性研究报告【申请可修改】.doc(106页珍藏版)》请在文库网上搜索。
1、rple; BOOL ColorizeCalendar(DayOfWeek today, Color todaysColor); ColorizeCalendar(blue, sunday); / 编译报错, Blue 和Sunday 位置错误 /不好的例子 : constint sunday = 0; constint monday = 1; constint black = 0; constint blue = 1; BOOL ColorizeCalendar(int today, int todaysColor); ColorizeCalendar(blue, sunday); / 不会
2、报错 当枚举值需要对应到具体数值时,须在声明时显示赋值。否则不需要显式赋值,以避免重复赋值, 降低维护 (增加、删除成员) 工作量。 示例: /好的例子: S协议里定义的设备ID 值,用于标识设备类型 enum TDeviceType DEV_UNKNOWN = -1, DEV_DSMP = 0, DEV_ISMG = 1, DEV_WAPPORTAL = 2 ; 程序内部使用,仅用于分类的情况,不应该进行显式的赋值。 示例: /好的例子:程序中用来标识会话状态的枚举定义 enum TSessionState SESSION_STATE_INIT, SESSION_STATE_CLOSED,
3、SESSION_STATE_WAITING_FOR_RSP ; 应当尽量避免枚举值重复,如必须重复也要用已定义的枚举来修饰,例如: typedef enum RTCP_SR = 200, RTCP_MIN_TYPE = RTCP_SR, /must be lowest known type RTCP_RR = 201, C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩散第8页,共57页 RTCP_SDES = 202, RTCP_BYE = 203, RTCP_APP = 204, RTCP_RTPFB = 205, RTCP_PSFB = 206, RTCP_XR =
4、 207, RTCP_RSI = 208, RTCP_PUBPORTS = 209, RTCP_MAX_TYPE = RTCP_PUBPORTS /must be highest known type rtcp_type_t; 规则 1.3 不相关的常量,即使取值一样,也必须分别定义 说明:一个常量只用来表示一个特定功能,即一个常量不能有多种用途。 示例: /好的例子:协议 A和协议 B,手机号 (MSISDN)的长度都是 20 。 unsignedconstint A_MAX_MSISDN_LEN = 20; unsignedconstint B_MAX_MSISDN_LEN = 20; /
5、或者使用不同的名字空间: namespace alib unsignedconstint MAX_MSISDN_LEN = 20; namespace blib unsignedconstint MAX_MSISDN_LEN = 20; 建议 1.1 尽可能使用 const 说明:在声明的变量或参数前加上关键字const 用于指明变量值不可被篡改。类成员函数加上const 限定符表明该函数不会修改类成员变量的状态。 使用 const 常见的场景: 函数参数:传递引用时,如果函数不会修改传入参数, 该形参应声明为const 。 成员函数:访问函数( 如get 函数 ) ;不修改任何数据成员的函数
6、;未调用非const 函数、未返回数 据成员的非 const 指针或引用的函数。 数据成员:如果数据成员在对象构造之后不再发生变化, 可将其定义为const 。 2 初始化和类型转换 2.1 声明、定义与初始化 规则 2.1 禁止用 memcpy 、memset初始化非 POD 对象 说明: POD 全称是“ Plain Old Data”,是 C+ 98标准 (ISO/IEC 14882, first edition, 1998-09-01) 中引入的一个概念, POD类型主要包括int, char, float,double ,enumeration ,void ,指针等原始 类型及其集合
7、类型,不能使用封装和面对对象特性(如用户定义的构造/ 赋值 / 析构函数、基类、虚函 数等)。 C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩散第9页,共57页 由于非 POD 类型比如非集合类型的class 对象,可能存在虚函数,内存布局不确定,跟编译器有关,滥 用内存拷贝可能会导致严重的问题。 即使对集合类型的class ,使用直接的内存拷贝和比较,破坏了信息隐蔽和数据保护的作用,也不提倡 memcpy 、memset操作。 示例:产品程序异常退出(core dump)。 经过现场环境的模似,程序产生COREDUMP,其原因是:在初始化函数内使用memset(th
8、is, 0, sizeof(*this)进行了类的初始化,将类的虚函数表指针被清空,从而导致使用空指针。 解决方案:使用C+构造函数初始化,不要使用memset函数初始化类对象。 建议 2.1 变量使用时才声明并初始化 说明:变量在使用前未赋初值,是常见的低级编程错误。使用前才声明变量并同时初始化,非常方便 地避免了此类低级错误。 在函数开始位置声明所有变量,后面才使用变量,作用域覆盖整个函数实现,容易导致如下问题: 程序难以理解和维护:变量的定义与使用分离。 变量难以合理初始化:在函数开始时,经常没有足够的信息进行变量初始化,往往用某个默认的 空值 (比如零 ) 来初始化, 这通常是一种浪费
9、,如果变量在被赋于有效值以前使用,还会导致错误。 遵循变量作用域最小化原则与就近声明原则,使得代码更容易阅读, 方便了解变量的类型和初始值。 特别是, 应使用初始化的方式替代声明再赋值。 示例: /不好的例子:声明与初始化分离 string name; /声明时未初始化:调用缺省构造函数 / . name= ” zhangsan” ; /再次调用赋值操作符函数;声明与定义在不同的地方,理解相对困难 /好的例子:声明与初始化一体,理解相对容易 string name(” zhangsan” ); /调用一次构造函数 建议 2.2 避免构造函数做复杂的初始化,可以使用“init”函数 说明:正如函
10、数的变量都在函数内部初始化一样,类数据成员最好的初始化场所就是构造函数,数据 成员都应该尽量在构造函数中初始化。 以下情况可以使用init()函数来初始化: 需要提供初始化返回信息。 数据成员初始化可能抛异常。 数据成员初始化失败会造成该类对象初始化失败,引起不确定状态。 数据成员初始化依赖this指针:构造函数没结束, 对象就没有构造出来,构造函数内不能使用this 成员; 数据成员初始化需要调用虚函数。在构造函数和析构函数中调用虚函数,会导致未定义的行为。 示例:数据成员初始化可能抛异常: class CPPRule C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩
11、散第10页,共57页 public: CPPRule():size_(0), res (null) ; / 仅进行值初始化 long init(int size) /根据传入的参数初始化size_, 分配资源 res private: int size_; ResourcePtr* res; ; /使用方法: CPPRule a; a.init(100); 建议 2.3 初始化列表要严格按照成员声明顺序来初始化它们 说明:编译器会按照数据成员在类定义中声明的顺序进行初始化,而不是按照初始化列表中的顺序, 如果打乱初始化列表的顺序实际上不起作用,但会造成阅读和理解上的混淆;特别是成员变量之间存
12、在依赖关系时可能导致BUG 。 示例: /不好的例子:初始化顺序与声明顺序不一致 class Employee public: Employee(constchar * firstName, constchar * lastName) : firstName_(firstName), lastName_(lastName) , email_(firstName_ + “.“ + lastName_ + “ “) ; private: string email_, firstName_, lastName_; ; 类定义 email_ 是在 firstName_, lastName_之前声明,它
13、将首先初始化,但使用了未初始化的 firstName_和lastName_ ,导致错误。 在成员声明时,应按照成员相互依赖关系按顺序声明。 建议 2.4 明确有外部依赖关系的全局与静态对象的初始化顺序 说明: 如果全局对象A的成员变量有外部依赖,比如依赖另外一个全局变量B,在A的构造函数中访问B, 隐含的规则就是B先于 A初始化,然而全局与静态对象的初始化与析构顺序未有严格定义,无法确保B 已经完成初始化,而每次生成可执行程序都可能发生变化,这类BUG 难以定位。 通常采用单件(Singleton)模式或者把有依赖关系的全局对象放在一个文件中定义来明确初始化顺序。 同一个文件中,若全局对象a在
14、全局对象 b之前定义,则a一定会在 b之前初始化;但是不同文件中的全 局对象就没有固定的初始化顺序。可以在main() 或 pthread_once() 内初始化一个运行期间不回收的 指针。 2.2 类型转换 避免使用类型分支来定制行为:类型分支来定制行为容易出错,是企图用C+编写 C代码的明显标志。 这是一种很不灵活的技术,要添加新类型时,如果忘记修改所有分支,编译器也不会告知。使用模板 和虚函数,让类型自己而不是调用它们的代码来决定行为。 C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩散第11页,共57页 规则 2.2 使用 C+风格的类型转换,不要使用C风格的类
15、型转换 说明: C+的类型转换由于采用关键字,更醒目,更容易查找,编程中强迫程序员多停留思考片刻,谨 慎使用强制转换。 C+使用 const_cast, dynamic_cast, static_cast, reinterpret_cast等新的类型转换,它们允许用 户选择适当级别的转换符,而不是像C那样全用一个转换符。 dynamic_cast:主要用于下行转换,dynamic_cast具有类型检查的功能。dynamic_cast有一定的开销, 建议在调测代码中使用。 static_cast:和C风格转换相似可做值的强制转换,或上行转换 ( 把派生类的指针或引用转换成基类的 指针或引用 )
16、。该转换经常用于消除多重继承带来的类型歧义,是相对安全的。下行转换( 把基类的指 针或引用转换成派生类的指针或引用) 时,由于没有动态类型检查,所以不安全的,不提倡下行转换。 reinterpret_cast:用于转换不相关的类型。reinterpret_cast强制编译器将某个类型对象的内存重 新解释成另一种类型,相关代码可移植不好。建议对reinterpret_cast 的用法进行注释,有助于减 少维护者在看到这种转换时的顾虑。 const_cast:用于移除对象的 const 属性,使对象变得可修改。 示例: externvoid Fun(DerivedClass* pd); void
17、Gun(BaseClass* pb) /不好的例子 : C 风格强制转换,转换会导致对象布局不一致,编译不报错,运行时可能会崩溃 DerivedClass* pd = (DerivedClass *)pb; /好的例子 : C+风格强制转换,明确知道pb实际指向 DerivedClass DerivedClass* pd = dynamic_cast(pb); if(pd) Fun(pd); 建议 2.5 避免使用 reinterpret_cast 说明: reinterpret_cast用于转换不相关类型。尝试用reinterpret_cast将一种类型强制转换另一种 类型,这破坏了类型的安
18、全性与可靠性,是一种不安全的转换。不同类型之间尽量避免转换。 建议 2.6 避免使用 const_cast 说明: const_cast用于移除对象的 const性质。 const 属性提供一种安全感,让程序员知道这个定义是固定不变的,从而不需要担心后面的变化。如果 const 属性在程序员不知道的地方被消除,会带来很多严重的后果。 示例:不好的例子 unsignedconst int arraySize = 1024; int newArraySize = 2048; 这里如果不通过引用或者指针访问arraySize,那么 arraySize的值始终是 1024。可是如果被作为一个 指针或者
19、引用传给其他函数进行取值的话,会发现值变成了2048。 示例:不好的例子:强制去掉入参的const 属性,导致函数可以对入参进行修改。 C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩散第12页,共57页 void setObj(TBase const *obj) /m_pObj的定义为 : TBase *m_pObj; m_pObj = const_cast(obj); m_pObj-value = 123; 建议 2.7 使用虚函数替换dynamic_cast 说明:很多刚从C 语言转过了的程序员习惯这样的思路:若对象的类型是T1,则做某种处理;若对象的 类型是 T
20、2,则做另外的处理等等。但C+提供了更好的解决方案:虚函数。 虚函数与 dynamic_cast类型转换相比: 虚函数更安全,不会出现强制转换错的情况; 虚函数效率更高:用函数指针,避免条件判断; 虚函数不需要在编码时确定对象的真实类型,而dynamic_cast 必须告知要转成的类型,运行时若 类型不当返回空指针或者抛异常; 虚函数适用性更强:虚函数是真正动态绑定;类型转换当增加或删除一个派生类时,dynamic_cast 必须增减相应的代码。 3 函数 3.1 内联函数 规则 3.1 内联函数 (inline function)小于 10行 说明:内联函数具有一般函数的特性,它与一般函数不
21、同之处只在于函数调用的处理。一般函数进行 调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时, 是将调用表达式用内联函数体来替换。 内联函数只适合于只有110行的小函数。 对一个含有许多语句的大函数,函数调用和返回的开销相对 来说微不足道,也没有必要用内联函数实现,一般的编译器会放弃内联方式,而采用普通的方式调用 函数。 如果内联函数包含复杂的控制结构,如循环、分支(switch)、try-catch等语句,一般编译器将该函数 视同普通函数。虚函数、递归函数不能被用来做内联函数。 规则 3.2 使用内联函数代替函数宏 说明: C+中也支持宏的功能,但是宏有其
22、自身固有的缺陷( 例如无法对参数进行类型检查) ,因此,能 使用内联函数的地方,一定不使用宏。 示例: /较好的例子 : template inline TYPE_T C+语言编程规范内部公开 2012-03-19 华为机密,未经许可不得扩散第13页,共57页 /不好的例子 : #define MAX(x,y)(x)(y)?(x):(y) 例外:一些通用且成熟的应用,如:对new, delete的封装处理,可以保留对宏的使用。 建议 3.1 内联函数应该放在头文件中声明,而且在函数前添加inline关键字 说明:内联函数的定义对编译器而言必须可见,以便在调用点将函数展开。放在头文件中可以保证对
23、 编译器可见,修改或者删除内联函数时,重新编译使用该头文件的所有源文件。 建议 3.2 内联函数的实现放在独立的文件 说明:确保接口清晰。如果使用者和维护者看见声明包含大量的内联实现,会干扰他们的思维,降低 声明的可读性和可维护性。所以除了最简单的成员存取函数外,其他较为复杂内联函数的实现放到独 立的头文件中( 建议使用 .inl为扩展名 ) ,在声明头文件的最后include。 /cpp_rule.h #ifndef CPP_RULE_H #define CPP_RULE_H class CppRule public: inline inlineFunction(); ; #include“
24、cpp_rule.inl” #endif /CPP_RULE_H /cpp_rule.inl #ifndef CPP_RULE_INL #define CPP_RULE_INL inline CppRule:inlineFunction() /内联函数实现 #endif /CPP_RULE_INL 3.2 函数参数 建议 3.3 入参尽量用 const 引用取代指针 说明:引用比指针更安全,因为它一定非空,且一定不会再指向其他目标;引用不需要检查非法的NULL 指针。 如果是基于老平台开发的产品,则优先顺从原有平台的处理方式。 选择 const 避免参数被修改,让代码阅读者清晰地知道该参数不被
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 申请可修改 变频 调用 膨胀 项目 可行性研究 报告 申请 修改