C++命名、编程规范
良好的代码编程命名、编程规范,可以提高代码的可读性,达到为读者服务的目的。参考 opencascade官方文档的推荐代码规范,学习一下C++编程中需要注意的编程规范,更好理解与使用OCC。
一、通用命名规则
名称应该有意义,或者至少包含一个有意义的部分。
1、驼峰命名法
驼峰命名风格是命名的首选。
Standard_Integer awidthofbox; // this is bad
Standard_Integer width_of_box; // this is bad
Standard_Integer aWidthOfBox; // this is OK
2、函数的命名
针对公共成员函数采用首字母大写开始命名,保护与私有成员函数采用首字母小写开始命名。
class MyPackage_MyClass
{
public:
Standard_Integer Value() const;
void SetValue (const Standard_Integer theValue);
private:
void setIntegerValue (const Standard_Integer theValue);
};
3、变量的命名
变量的命名有几种格式。
但是需要注意:
(1)变量的名称不应与现有或可能的全局名称冲突;
(2)变量的名称不应以下划线开头;
Standard_Integer Elapsed_Time = 0; // this is bad - possible class name
Standard_Integer gp = 0; // this is bad - existing package name
Standard_Integer aGp = 0; // this is OK
Standard_Integer _KERNEL = 0; // this is bad
Standard_Integer THE_KERNEL = 0; // this is OK
4、函数的参数命名
函数参数的名称应该以 the 为前缀,后接名称有意义的部分且以大写字母开头。
void Package_MyClass::MyFunction (const gp_Pnt& p); // this is bad
void Package_MyClass::MyFunction (const gp_Pnt& theP); // this is OK
void Package_MyClass::MyFunction (const gp_Pnt& thePoint); // this is preferred
5、类的成员变量命名
类成员变量的名称应该以 my 为前缀,后接以大写字母开头的名称有意义部分。
Standard_Integer counter; // This is bad
Standard_Integer myC; // This is OK
Standard_Integer myCounter; // This is preferred
6、全局变量的命名
建议避免定义任何全局变量。 但是,一旦需要定义必要的全局变量,它的名称应该是由类的名称,其中包含 _my。
Standard_Integer MyPackage_myGlobalVariable = 0;
Standard_Integer MyPackage_MyClass_myGlobalVariable = 0;
静态常量应以大写字母编写,并以前缀 THE_开头:
namespace
{
static const Standard_Real THE_CONSTANT_COEF = 3.14;
};
7、局部变量的命名
应从函数参数,类成员变量和全局变量的名称可区分局部变量的名称,
优选的是,前面加上局部变量名 a、an(或 is、to和 has 用于布尔变量。
Standard_Integer theI; // this is bad
Standard_Integer i; // this is bad
Standard_Integer index; // this is bad
Standard_Integer anIndex; // this is OK
8、避免使用虚拟名称
避免虚拟名称,例如i,j,k。 这些名称毫无意义且易于混淆。
9、参考代码规范
void Average (const Standard_Real** theArray,
Standard_Integer theRowsNb,
Standard_Integer theRowLen,
Standard_Real& theResult)
{
theResult = 0.0;
for (Standard_Integer aRow = 0; aRow < aRowsNb; ++aRow)
{
for (Standard_Integer aCol = 0; aCol < aRowLen; ++aCol)
{
theResult += theArray[aRow][aCol];
}
theResult /= Standard_Real(aRowsNb * aRowLen);
}
}
二、格式规范
为了提高代码的可读性、有序性和可维护性
1、符号之间的“空格”运用
在vs中自动为我们提供了格式的缩进,我们也应该了解符号使用时,space的使用场合。
(1)C / C ++的保留单词(while、if等),逗号,冒号和分号应该应该后接空格字符,如果它们不是在线的末尾;
(2)“(”和“)”的前后应该无空格符。
while (true) // NOT: while( true ) ...
{
DoSomething (theA, theB, theC, theD); // NOT: DoSomething(theA,theB,theC,theD);
}
for (anIter = 0; anIter < 10; ++anIter) // NOT: for (anIter=0;anIter<10;++anIter){
{
theA = (theB + theC) * theD; // NOT: theA=(theB+theC)*theD
}
2、指针的声明和引用
(1)指针与引用的符号直接接在数据类型后面,而不加空格;
(2)不同的指针声明公开声明,不建议统一声明。
Standard_Integer *theVariable; // not recommended
Standard_Integer * theVariable; // not recommended
Standard_Integer* theVariable; // this is OK
Standard_Integer *&theVariable; // not recommended
Standard_Integer *& theVariable; // not recommended
Standard_Integer*& theVariable; // this is OK
Standard_Integer **theVariable; // not recommended
Standard_Integer ** theVariable; // not recommended
Standard_Integer** theVariable; // this is OK
Standard_Integer *theA, theB, **theC; // not recommended (declare each variable independently)
3、单独代码块的注释
单独的逻辑代码块,带有一个空白行和注释,应避免多条空白行。
// check arguments
Standard_Integer anArgsNb = argCount();
if (anArgsNb < 3 || isSmthInvalid)
{
return THE_ARG_INVALID;
}
// read and check header
...
...
// do our job
...
..
4、函数体分隔
使用功能描述注释块将函数体彼此分隔开。 每个描述性块至少应至少包含函数名称和用途说明。
// =======================================================================
// function : TellMeSmthGood
// purpose : Gives me good news
// =======================================================================
void TellMeSmthGood()
{
...
}
// =======================================================================
// function : TellMeSmthBad
// purpose : Gives me bad news
// =======================================================================
void TellMeSmthBad()
{
...
}
5、代码块分布
{ } ,for, if, else, try,和catch 等代码块建议放在单独一行。
while (expression)
{
...
}
if (!myIsInit) return Standard_False; // bad
if (thePtr == NULL) // OK
return Standard_False;
if (!theAlgo.IsNull()) // preferred
{
DoSomething();
}
6、与常量的比较表达式
在比较中,将变量放在表达式左侧,常量放在表达式右侧。
if (NULL != thePointer) // Yoda style, not recommended
if (thePointer != NULL) // OK
if (34 < anIter) // Yoda style, not recommended
if (anIter > 34) // OK
if (theNbValues >= anIter) // bad style (constant function argument vs. local variable)
if (anIter <= theNbValues) // OK
if (THE_LIMIT == theValue) // bad style (global constant vs. variable)
if (theValue == THE_LIMIT) // OK
7、语句对齐
各代码行之间对应项对齐
MyPackage_MyClass anObject;
Standard_Real aMinimum = 0.0;
Standard_Integer aVal = theVal;
switch (aVal)
{
case 0: computeSomething(); break;
case 12: computeSomethingElse (aMinimum); break;
case 3:
default: computeSomethingElseYet(); break;
}
8、代码的注释
注释语句应该紧贴代码行,当代码行过短时,可以在其后注释,一般情况放在之前注释。
while (expression) //bad comment
{
// this is a long multi-line comment
// which is really required
DoSomething(); // maybe, enough
DoSomethingMore(); // again
}
9、return的时机
尽可能将return放在代码块靠前的位置,避免不必要的运行开销。
推荐:
Standard_Integer ComputeSumm (const Standard_Integer* theArray,
const Standard_Size theSize)
{
Standard_Integer aSumm = 0;
if (theArray == NULL || theSize == 0)
{
return 0;
}
... computing summ ...
return aSumm;
}
不推荐
Standard_Integer ComputeSumm (const Standard_Integer* theArray,
const Standard_Size theSize)
{
Standard_Integer aSumm = 0;
if (theArray != NULL && theSize != 0)
{
... computing summ ...
}
return aSumm;
}
10、头文件的包含
项目使用不同的库时,将不同类型的头文件分开包含可以使条例更加清晰。
// the header file of implemented class
#include <PackageName_ClassName.hxx>
// OCCT headers
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <NCollection_List.hxx>
// Qt headers
#include <QDataStream>
#include <QString>
// system headers
#include <iostream>
#include <windows.h>
三、文档规范
1、在for()之前声明变量
在for()语句之前声明一个循环变量。
Standard_Real aMinDist = Precision::Infinite();
for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter (theSequence);
aPntIter.More(); aPntIter.Next())
{
aMinDist = Min (aMinDist, theOrigin.Distance (aPntIter.Value()));
}
2、避免在if()语句中使用非0条件
避免使用非布尔变量的C样式比较。
void Function (Standard_Integer theValue,
Standard_Real* thePointer)
{
if (!theValue) // bad style - ambiguous logic
{
DoSome();
}
if (theValue == 0) // OK
{
DoSome();
}
if (thePointer != NULL) // OK, predefined NULL makes pointer comparison cleaner to reader
{ // (nullptr should be used instead as soon as C++11 will be available)
DoSome2();
}
}
3、成员变量初始化顺序
按照声明的顺序进行初始化
class MyPackage_MyClass
{
public:
MyPackage_MyClass()
: myPropertyA (1),
myPropertyB (2) {}
// NOT
// : myPropertyB (2),
// myPropertyA (1) {}
private:
Standard_Integer myPropertyA;
Standard_Integer myPropertyB;
};
初始化的格式:
MyPackage_MyClass()
: myPropertyA (1) // preferred
{
myPropertyB = 2; // not recommended
}
4、代码示例
class Package_Class
{
public: //! @name public methods
//! Method computes the square value.
//! @param theValue the input value
//! @return squared value
Standard_Export Standard_Real Square (const Standard_Real theValue);
private: //! \@name private methods
//! Auxiliary method
void increment();
private: //! \@name private fields
Standard_Integer myCounter; //!< usage counter
};
#include <Package_Class.hxx>
// ==========================================================
// function : Square
// purpose : Method computes the square value
// ==========================================================
Standard_Real Package_Class::Square (const Standard_Real theValue)
{
increment();
return theValue * theValue;
}
// ==========================================================
// function : increment
// purpose :
// ==========================================================
void Package_Class::increment()
{
++myCounter;
}