C++编程规范华为Word文档已整理过07my04.docx
- 文档编号:5731912
- 上传时间:2022-12-31
- 格式:DOCX
- 页数:77
- 大小:80.30KB
C++编程规范华为Word文档已整理过07my04.docx
《C++编程规范华为Word文档已整理过07my04.docx》由会员分享,可在线阅读,更多相关《C++编程规范华为Word文档已整理过07my04.docx(77页珍藏版)》请在冰豆网上搜索。
C++编程规范华为Word文档已整理过07my04
1.1C++编程规范总则
1.1.1资料来源
分类:
编码规范C/C++2012-09-1712:
49101人阅读评论(0)收藏举报
编程c++
C++编程规范专辑:
1.1.2C++编程规范总则
1.原则:
编程时必须坚持的指导思想。
2.规则:
编程时强制必须遵守的约定。
3.建议:
编程时必须加以考虑的约定。
4.说明:
对此原则/规则/建议进行必要的解释。
5.示例:
对此原则/规则/建议从好、不好两个方面给出例子。
6.延伸阅读材料:
建议进一步阅读的参考材料。
1.2C++编程规范1常量
1.2.1资料来源
分类:
C/C++编码规范2012-09-1712:
50369人阅读评论
(2)收藏举报
c++编程session编译器工作手机
1.2.2C++编程规范1常量
不变的值更易于理解、跟踪和分析,所以应该尽可能地使用常量代替变量,定义值的时候,应该把const作为默认的选项。
1.规则1.1使用const常量取代宏
说明:
宏是简单的文本替换,在预处理阶段时完成,运行报错时直接报相应的值;跟踪调试时也是显示值,而不是宏名;宏没有类型检查,不安全;宏没有作用域。
示例:
#defineMAX_MSISDN_LEN(20)//不好的例子
constintMAX_MSISDN_LEN=20;//好的例子
2.规则1.2一组相关的整型常量应定义为枚举
说明:
之所以使用枚举,基于:
枚举比#define或constint更安全,因为编译器会检查参数值是否位于枚举取值范围内,从而避免错误发生。
示例:
//好的例子:
enumDayOfWeek{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
enumColor{black,blue,white,red,purple};
BOOLColorizeCalendar(DayOfWeektoday,ColortodaysColor);
ColorizeCalendar(blue,sunday);//编译报错,Blue和Sunday位置错误
//不好的例子:
constintsunday=0;
constintmonday=1;
constintblack=0;
constintblue=1;
BOOLColorizeCalendar(inttoday,inttodaysColor);
ColorizeCalendar(blue,sunday);//不会报错
当枚举值需要对应到具体数值时,须在声明时显示赋值。
否则不需要显式赋值,以避免重复赋值,降低维护(增加、删除成员)工作量。
示例:
//好的例子:
S协议里定义的设备ID值,用于标识设备类型
enumTDeviceType
{
DEV_UNKNOWN=-1,
DEV_DSMP=0,
DEV_ISMG=1,
DEV_WAPPORTAL=2
};
程序内部使用,仅用于分类的情况,不应该进行显式的赋值。
示例:
//好的例子:
程序中用来标识会话状态的枚举定义
enumTSessionState
{
SESSION_STATE_INIT,
SESSION_STATE_CLOSED,
SESSION_STATE_WAITING_FOR_RSP
};
应当尽量避免枚举值重复,如必须重复也要用已定义的枚举来修饰,例如:
typedefenum
{
RTCP_SR=200,
RTCP_MIN_TYPE=RTCP_SR,//mustbelowestknowntype
RTCP_RR=201,
RTCP_SDES=202,
RTCP_BYE=203,
RTCP_APP=204,
RTCP_RTPFB=205,
RTCP_PSFB=206,
RTCP_XR=207,
RTCP_RSI=208,
RTCP_PUBPORTS=209,
RTCP_MAX_TYPE=RTCP_PUBPORTS//mustbehighestknowntype
}rtcp_type_t;
3.规则1.3不相关的常量,即使取值一样,也必须分别定义
说明:
一个常量只用来表示一个特定功能,即一个常量不能有多种用途。
示例:
//好的例子:
协议A和协议B,手机号(MSISDN)的长度都是20。
unsignedconstintA_MAX_MSISDN_LEN=20;
unsignedconstintB_MAX_MSISDN_LEN=20;
//或者使用不同的名字空间:
namespacealib
{
unsignedconstintMAX_MSISDN_LEN=20;
}
namespaceblib
{
unsignedconstintMAX_MSISDN_LEN=20;
}
4.建议1.1尽可能使用const
说明:
在声明的变量或参数前加上关键字const用于指明变量值不可被篡改。
类成员函数加上const限定符表明该函数不会修改类成员变量的状态。
使用const常见的场景:
A.函数参数:
传递引用时,如果函数不会修改传入参数,该形参应声明为const。
B.成员函数:
访问函数(如get函数);不修改任何数据成员的函数;未调用非const函数、未返回数据成员的非const指针或引用的函数。
C.数据成员:
如果数据成员在对象构造之后不再发生变化,可将其定义为const。
1.3C++编程规范2初始化和类型转换
资料来源:
分类:
C/C++编码规范2012-09-1712:
52471人阅读评论(0)收藏举报
编程c++编译器classstringemail
1.3.12.1声明、定义与初始化
1.规则2.1禁止用memcpy、memset初始化非POD对象
说明:
POD全称是“PlainOldData”,是C++98标准(ISO/IEC14882,firstedition,1998-09-01)中引入的一个概念,POD类型主要包括int,char,float,double,enumeration,void,指针等原始类型及其集合类型,不能使用封装和面对对象特性(如用户定义的构造/赋值/析构函数、基类、虚函数等)。
由于非POD类型比如非集合类型的class对象,可能存在虚函数,内存布局不确定,跟编译器有关,滥用内存拷贝可能会导致严重的问题。
即使对集合类型的class,使用直接的内存拷贝和比较,破坏了信息隐蔽和数据保护的作用,也不提倡memcpy、memset操作。
示例:
×××产品程序异常退出(coredump)。
经过现场环境的模似,程序产生COREDUMP,其原因是:
在初始化函数内使用memset(this,0,sizeof(*this))进行了类的初始化,将类的虚函数表指针被清空,从而导致使用空指针。
解决方案:
使用C++构造函数初始化,不要使用memset函数初始化类对象。
2.建议2.1变量使用时才声明并初始化
说明:
变量在使用前未赋初值,是常见的低级编程错误。
使用前才声明变量并同时初始化,非常方便地避免了此类低级错误。
在函数开始位置声明所有变量,后面才使用变量,作用域覆盖整个函数实现,容易导致如下问题:
程序难以理解和维护:
变量的定义与使用分离。
变量难以合理初始化:
在函数开始时,经常没有足够的信息进行变量初始化,往往用某个默认的空值(比如零)来初始化,这通常是一种浪费,如果变量在被赋于有效值以前使用,还会导致错误。
遵循变量作用域最小化原则与就近声明原则,使得代码更容易阅读,方便了解变量的类型和初始值。
特别是,应使用初始化的方式替代声明再赋值。
示例:
//不好的例子:
声明与初始化分离
stringname;//声明时未初始化:
调用缺省构造函数
//…….
name=”zhangsan”;//再次调用赋值操作符函数;声明与定义在不同的地方,理解相对困难
//好的例子:
声明与初始化一体,理解相对容易
stringname(”zhangsan”);//调用一次构造函数
3.建议2.2避免构造函数做复杂的初始化,可以使用“init”函数
说明:
正如函数的变量都在函数内部初始化一样,类数据成员最好的初始化场所就是构造函数,数据成员都应该尽量在构造函数中初始化。
以下情况可以使用init()函数来初始化:
需要提供初始化返回信息。
数据成员初始化可能抛异常。
数据成员初始化失败会造成该类对象初始化失败,引起不确定状态。
数据成员初始化依赖this指针:
构造函数没结束,对象就没有构造出来,构造函数内不能使用this成员;
数据成员初始化需要调用虚函数。
在构造函数和析构函数中调用虚函数,会导致未定义的行为。
示例:
数据成员初始化可能抛异常:
classCPPRule
{
public:
CPPRule():
size_(0),res(null){};//仅进行值初始化
longinit(intsize)
{
//根据传入的参数初始化size_,分配资源res
}
private:
intsize_;
ResourcePtr*res;
};
//使用方法:
CPPRulea;
a.init(100);
4.建议2.3初始化列表要严格按照成员声明顺序来初始化它们
说明:
编译器会按照数据成员在类定义中声明的顺序进行初始化,而不是按照初始化列表中的顺序,如果打乱初始化列表的顺序实际上不起作用,但会造成阅读和理解上的混淆;特别是成员变量之间存在依赖关系时可能导致BUG。
示例:
//不好的例子:
初始化顺序与声明顺序不一致
classEmployee
{
public:
Employee(constchar*firstName,constchar*lastName)
:
firstName_(firstName),lastName_(lastName),email_(firstName_+"."+lastName_+"@")
{};
private:
stringemail_,firstName_,lastName_;
};
类定义email_是在firstName_,lastName_之前声明,它将首先初始化,但使用了未初始化的firstName_和lastName_,导致错误。
在成员声明时,应按照成员相互依赖关系按顺序声明。
5.建议2.4明确有外部依赖关系的全局与静态对象的初始化顺序
说明:
如果全局对象A的成员变量有外部依赖,比如依赖另外一个全局变量B,在A的构造函数中访问B,隐含的规则就是B先于A初始化,然而全局与静态对象的初始化与析构顺序未有严格定义,无法确保B已经完成初始化,而每次生成可执行程序都可能发生变化,这类BUG难以定位。
通常采用单件(Singleton)模式或者把有依赖关系的全局对象放在一个文件中定义来明确初始化顺序。
同一个文件中,若全局对象a在全局对象b之前定义,则a一定会在b之前初始化;但是不同文件中的全局对象就没有固定的初始化顺序。
可以在main()或pthread_once()内初始化一个运行期间不回收的指针。
1.3.22.2类型转换
避免使用类型分支来定制行为:
类型分支来定制行为容易出错,是企图用C++编写C代码的明显标志。
这是一种很不灵活的技术,要添加新类型时,如果忘记修改所有分支,编译器也不会告知。
使用模板和虚函数,让类型自己而不是调用它们的代码来决定行为。
1.规则2.2使用C++风格的类型转换,不要使用C风格的类型转换
说明:
C++的类型转换由于采用关键字,更醒目,更容易查找,编程中强迫程序员多停留思考片刻,谨慎使用强制转换。
C++使用const_cast,dynamic_cast,static_cast,reinterpret_cast等新的类型转换,它们允许用户选择适当级别的转换符,而不是像C那样全用一个转换符。
dynamic_cast:
主要用于下行转换,dynamic_cast具有类型检查的功能。
dynamic_cast有一定的开销,建议在调测代码中使用。
static_cast:
和C风格转换相似可做值的强制转换,或上行转换(把派生类的指针或引用转换成基类的指针或引用)。
该转换经常用于消除多重继承带来的类型歧义,是相对安全的。
下行转换(把基类的指针或引用转换成派生类的指针或引用)时,由于没有动态类型检查,所以不安全的,不提倡下行转换。
reinterpret_cast:
用于转换不相关的类型。
reinterpret_cast强制编译器将某个类型对象的内存重新解释成另一种类型,相关代码可移植不好。
建议对reinterpret_cast<>的用法进行注释,有助于减少维护者在看到这种转换时的顾虑。
const_cast:
用于移除对象的const属性,使对象变得可修改。
示例:
externvoidFun(DerivedClass*pd);
voidGun(BaseClass*pb)
{
//不好的例子:
C风格强制转换,转换会导致对象布局不一致,编译不报错,运行时可能会崩溃
DerivedClass*pd=(DerivedClass*)pb;
//好的例子:
C++风格强制转换,明确知道pb实际指向DerivedClass
DerivedClass*pd=dynamic_cast
if(pd)
Fun(pd);
}
2.建议2.5避免使用reinterpret_cast
说明:
reinterpret_cast用于转换不相关类型。
尝试用reinterpret_cast将一种类型强制转换另一种类型,这破坏了类型的安全性与可靠性,是一种不安全的转换。
不同类型之间尽量避免转换。
3.建议2.6避免使用const_cast
说明:
const_cast用于移除对象的const性质。
const属性提供一种安全感,让程序员知道这个定义是固定不变的,从而不需要担心后面的变化。
如果const属性在程序员不知道的地方被消除,会带来很多严重的后果。
示例:
不好的例子
unsignedconstintarraySize=1024;
int&newArraySize=const_cast
newArraySize=2048;
这里如果不通过引用或者指针访问arraySize,那么arraySize的值始终是1024。
可是如果被作为一个指针或者引用传给其他函数进行取值的话,会发现值变成了2048。
示例:
不好的例子:
强制去掉入参的const属性,导致函数可以对入参进行修改。
voidsetObj(TBaseconst*obj)
{
//m_pObj的定义为:
TBase*m_pObj;
m_pObj=const_cast
m_pObj->value=123;
}
4.建议2.7使用虚函数替换dynamic_cast
说明:
很多刚从C语言转过了的程序员习惯这样的思路:
若对象的类型是T1,则做某种处理;若对象的类型是T2,则做另外的处理等等。
但C++提供了更好的解决方案:
虚函数。
虚函数与dynamic_cast类型转换相比:
A.虚函数更安全,不会出现强制转换错的情况;
B.虚函数效率更高:
用函数指针,避免条件判断;
C.虚函数不需要在编码时确定对象的真实类型,而dynamic_cast必须告知要转成的类型,运行时若类型不当返回空指针或者抛异常;
D.虚函数适用性更强:
虚函数是真正动态绑定;类型转换当增加或删除一个派生类时,dynamic_cast必须增减相应的代码。
1.4C++编程规范3函数
资料来源:
分类:
C/C++编码规范2012-09-1712:
53219人阅读评论(0)收藏举报
c++编程编译器classinclude扩展
1.4.13.1内联函数
1.规则3.1内联函数(inlinefunction)小于10行
说明:
内联函数具有一般函数的特性,它与一般函数不同之处只在于函数调用的处理。
一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。
内联函数只适合于只有1~10行的小函数。
对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,也没有必要用内联函数实现,一般的编译器会放弃内联方式,而采用普通的方式调用函数。
如果内联函数包含复杂的控制结构,如循环、分支(switch)、try-catch等语句,一般编译器将该函数视同普通函数。
虚函数、递归函数不能被用来做内联函数。
2.规则3.2使用内联函数代替函数宏
说明:
C++中也支持宏的功能,但是宏有其自身固有的缺陷(例如无法对参数进行类型检查),因此,能使用内联函数的地方,一定不使用宏。
示例:
//较好的例子:
template
{
return(x>y)?
x:
y;
}
//不好的例子:
#defineMAX(x,y)((x)>(y)?
(x):
(y))
例外:
一些通用且成熟的应用,如:
对new,delete的封装处理,可以保留对宏的使用。
3.建议3.1内联函数应该放在头文件中声明,而且在函数前添加inline关键字
说明:
内联函数的定义对编译器而言必须可见,以便在调用点将函数展开。
放在头文件中可以保证对编译器可见,修改或者删除内联函数时,重新编译使用该头文件的所有源文件。
4.建议3.2内联函数的实现放在独立的文件
说明:
确保接口清晰。
如果使用者和维护者看见声明包含大量的内联实现,会干扰他们的思维,降低声明的可读性和可维护性。
所以除了最简单的成员存取函数外,其他较为复杂内联函数的实现放到独立的头文件中(建议使用.inl为扩展名),在声明头文件的最后include。
//cpp_rule.h
#ifndefCPP_RULE_H
#defineCPP_RULE_H
classCppRule
{
public:
inlineinlineFunction();
};
#include“cpp_rule.inl”
#endif//CPP_RULE_H
//cpp_rule.inl
#ifndefCPP_RULE_INL
#defineCPP_RULE_INL
inlineCppRule:
:
inlineFunction()
{
//内联函数实现
}
#endif//CPP_RULE_INL
1.4.23.2函数参数
1.建议3.3入参尽量用const引用取代指针
说明:
引用比指针更安全,因为它一定非空,且一定不会再指向其他目标;引用不需要检查非法的NULL指针。
如果是基于老平台开发的产品,则优先顺从原有平台的处理方式。
选择const避免参数被修改,让代码阅读者清晰地知道该参数不被修改,可大大增强代码可读性。
2.建议3.4消除未使用函数参数
说明:
检查未使用的函数参数,确认是否需要使用该函数参数,如果不需要直接删除参数名。
当实现接口时,有一些参数没有被引用是相当常见的。
编译器会发现未使用的参数,并产生一个警告,有些组件甚至会认为这是一个错误。
为避免发生如此情况,将未使用的参数使用/*参数名*/语法将其注释掉。
示例:
//好的例子:
将localityHint参数名去掉,在注释中保留参数名以备参考和理解参数含义
pointerallocate(size_typenumObjects,constvoid*/*localityHint*/=0)
{
returnstatic_cast
}
3.建议3.5尽量少用缺省参数
说明:
使用参数的缺省值仅仅方便函数的使用,没有赋予函数新的功能,但降低函数的可理解。
缺省参数使得拷贝粘贴以前函数调用的代码难以呈现所有参数,当缺省参数不适用于新代码时可能导致重大问题。
1.4.33.3函数指针
1.建议3.6尽量少用函数指针
说明:
不少代码中还是用函数指针来实现一些功能扩展(如封装),但函数指针难以理解和难以维护,建议使用C++中派生与继承的基本用法,少用函数指针。
1.5C++编程规范4类
资料来源:
分类:
C/C++编码规范2012-09-1712:
54246人阅读评论(0)收藏举报
编程c++stringclassdeleteinheritance
1.5.14.1类的设计
类是面向对象设计的基础,一个好的类应该职责单一,接口清晰、少而完备,类间低耦合、类内高内聚,并且很好地展现封装、继承、多态、模块化等特性。
1.原则4.1类职责单一
说明:
类应该职责单一。
如果一个类的职责过多,往往难以设计、实现、使用、维护。
随着功能的扩展,类的职责范围自然也扩大,但职责不应该发散。
用小类代替巨类。
小类更易于编写,测试,使用和维护。
用小类体现简单设计的概念;巨类会削弱封装性,巨类往往承担过多职责,试图提供“完整”的解决方案,但往往难以真正成功。
如果一个类有10个以上数据成员,类的职责可能过多。
2.原则4.2隐藏信息
说明:
封装是面向对象设计和编程的核心概念之一。
隐藏实现的内部数据,减少调用者代码与具体实现代码之间的依赖。
A.尽量减少全局和共享数据;
B.禁止成员函数返回成员可写的引用或者指针;
C.将数据成员设为私有的(struct除外),并提供相关存取函数;
D.避免为每个类数据成员提供访问函数;
E.运行时多态,将内部实现(派生类提供)与对外接口(基类提供)分离。
3.原则4.3尽量使类的接口正交、少而完备
说明:
应该围绕一个核心去定义接口、提供服务、与其他类合作,从而易于
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 编程 规范 华为 Word 文档 整理 07 my04