类的非常量数据成员均应为 private
5.1.1 ID_nonPrivateData
类的数据成员均应设为 private,统一由成员函数提供访问方法,并避免返回数据成员的非常量引用或指针。
将类的所有接口都实现为成员函数,由成员函数按指定逻辑读写数据,以便保证有效地改变对象状态。良好的接口设计会对代码的职责进行合理划分,显著提升可维护性。理想状态下,当有错误需要修正或有功能需要调整时,只改动相关接口的实现即可,调用接口的代码不需要改动,从而将改动降到最低。这种设计的基础便是将数据设为 private,只能由本类的成员函数访问,否则数据可被各个模块随意读写,当有一处需要改动时,很难控制其影响范围。
另外,充分隐藏数据的内部细节也是重要的安全保障,可以有效避免攻击者窃取数据或引发程序的意外行为。
常量数据成员不可被改变,所以可不受本规则约束。
示例:
struct A {
int *p, n; // Non-compliant
A(int n): p(new int[n]), n(n) {}
~A() { delete[] p; }
};
例中类的数据成员 p 指向动态分配的内存区域,n 记录区域大小,p 和 n 之间存在紧密的逻辑关系,这种内在关系应由成员函数统一维护,不暴露给类的使用者,这便是面向对象的封装理念,也是 C++ 语言的核心理念之一。
应改为:
class A {
int *p, n; // Compliant
public:
A(int n): p(new int[n]), n(n) {}
~A() { delete[] p; }
int* begin() { return p; } // Interfaces for members
int* end() { return p + n; }
};
这样数据成员不能被外界直接访问,成员之间的关系也不会被随意打破,显著提升可维护性。
相关
参考
CWE-1061
MISRA C++ 2008 11-0-1