C++语言编程规范-常量
01 C++还有搞头吗
02 常量
不变的值更易于理解、跟踪和分析,所以应该尽可能地使用常量代替变量,定义值的时候,应该把 const 作为默认的选项。
使用 const 常量取代宏
说明:宏是简单的文本替换,在预处理阶段时完成,运行报错时直接报相应的值;跟踪调试时也是显示值,而不是宏名;宏没有类型检查,不安全;宏没有作用域。
示例:
#define MAX_MSISDN_LEN (20) //不好的例子const int MAX_MSISDN_LEN = 20; //好的例子
03
一组相关的整型常量应定义为枚举
说明:之所以使用枚举,基于:
⚫
枚举比#define 或 const int 更安全,因为编译器会检查参数值是否是否位于枚举取值范围内,从而避免错误发生。
示例:
//好的例子:enum DayOfWeek{sunday,monday, tuesday, wednesday, thursday, friday, saturday};enum Color{black, blue, white, red, purple};BOOL ColorizeCalendar(DayOfWeek today, Color todaysColor);ColorizeCalendar(blue, sunday); //编译报错,Blue和Sunday位置错误//不好的例子:const int sunday = 0;const int monday = 1;const int black = 0;const int blue = 1;BOOL ColorizeCalendar(int today, int todaysColor);ColorizeCalendar(blue, sunday); //不会报错
⚫
当枚举值需要对应到具体数值时,须在声明时显示赋值。否则不需要显式赋值,以避免重复赋值,降低维护(增加、删除成员)工作量。
示例:
//好的例子:S协议里定义的设备ID值,用于标识设备类型enum TDeviceType{DEV_UNKNOWN = -1,DEV_DSMP = 0,DEV_ISMG = 1,DEV_WAPPORTAL = 2};//好的例子:程序中用来标识会话状态的枚举定义enum TSessionState{SESSION_STATE_INIT,SESSION_STATE_CLOSED,SESSION_STATE_WAITING_FOR_RSP};
⚫
应当尽量避免枚举值重复,如必须重复也要用已定义的枚举来修饰,例如:
typedef enum{RTCP_SR = 200,RTCP_MIN_TYPE = RTCP_SR, //must be lowest known typeRTCP_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 //must be highest known} rtcp_type_t;
04
不相关的常量,即使取值一样,也必须分别定义
说明:一个常量只用来表示一个特定功能,即一个常量不能有多种用途。
示例:
//好的例子:协议A和协议B,手机号(MSISDN)的长度都是20。unsigned const int A_MAX_MSISDN_LEN = 20;unsigned const int B_MAX_MSISDN_LEN = 20;//或者使用不同的名字空间:namespace alib{const int MAX_MSISDN_LEN = 20;}namespace blib{const int MAX_MSISDN_LEN = 20;}
05
尽可能使用 const
说明:
在声明的变量或参数前加上关键字 const 用于指明变量值不可被篡改。
类成员函数加上 const 限定符表明该函数不会修改类成员变量的状态。
使用 const 常见的场景:
⚫ 函数参数:传递引用时,如果函数不会修改传入参数, 该形参应声明为 const。
void printValue(const int& value) { // 正确:不需要修改valuestd::cout << value << std::endl;// value = 10; // 错误:不能修改const参数
}
int main() {int x = 5;const int y = 10;printValue(x); // 可以传递非const变量printValue(y); // 可以传递const变量printValue(42); // 可以传递临时值return 0;
}
⚫ 成员函数:访问函数(如 get 函数);不修改任何数据成员的函数;未调用非 const 函数、未返回数据成员的非 const 指针或引用的函数。
class MyClass {private:int value;mutable int cache; // 即使在const函数中也可以修改mutable bool cacheValid;public:MyClass(int v) : value(v), cache(0), cacheValid(false) {}// 正确的const成员函数示例int getValue() const {return value; // 只读取,不修改}int getValueWithCache() const {if (!cacheValid) {cache = value * 2; // 修改mutable成员是允许的cacheValid = true;}return cache;}// 错误示例:这个函数修改了数据成员,不能是constvoid setValue(int v) {value = v;}// 错误示例:这个函数调用了非const成员函数,不能是constvoid updateAndGetValue() const {setValue(10); // 错误:不能在const函数中调用非const函数}// 错误示例:返回了非const引用,不能是constint& getValueRef() const {return value; // 错误:返回了非const引用}// 正确示例:返回const引用const int& getValueRef() const {return value; // 正确:返回const引用}};int main() {const MyClass obj(5);int val = obj.getValue(); // 正确:可以在const对象上调用const成员函数// obj.setValue(10); // 错误:不能在const对象上调用非const成员函数return 0;}
⚫ 数据成员:如果数据成员在对象构造之后不再发生变化, 可将其定义为 const。
class Circle {private:const double radius; // 半径在构造后不应改变const double pi; // π值恒定不变double x, y; // 位置可以改变public:Circle(double r, double x, double y): radius(r), pi(3.141592653589793), x(x), y(y) {// 在构造函数初始化列表中初始化const成员}double getArea() const {return pi * radius * radius; // 可以使用const成员}void move(double newX, double newY) {x = newX; // 可以修改非const成员y = newY;}// 错误示例:试图修改const成员void setRadius(double newRadius) {// radius = newRadius; // 错误:不能修改const成员}};int main() {Circle c(5.0, 0.0, 0.0);double area = c.getArea(); // 正确:可以访问const成员// c.radius = 10.0; // 错误:不能修改const成员return 0;}class Circle {private:const double radius; // 半径在构造后不应改变const double pi; // π值恒定不变double x, y; // 位置可以改变public:Circle(double r, double x, double y): radius(r), pi(3.141592653589793), x(x), y(y) {// 在构造函数初始化列表中初始化const成员}double getArea() const {return pi * radius * radius; // 可以使用const成员}void move(double newX, double newY) {x = newX; // 可以修改非const成员y = newY;}// 错误示例:试图修改const成员void setRadius(double newRadius) {// radius = newRadius; // 错误:不能修改const成员}};int main() {Circle c(5.0, 0.0, 0.0);double area = c.getArea(); // 正确:可以访问const成员// c.radius = 10.0; // 错误:不能修改const成员return 0;}