一、主要观点:
- 成员变量应该声明为
private
,而不是public
或protected
。
二、具体解释:
-
封装性:
- 信息隐藏:将成员变量声明为
private
有助于实现信息隐藏。这样可以将类的内部实现细节隐藏起来,只暴露必要的接口给外部使用,避免外部代码直接依赖类的内部实现细节。例如,你可以在不影响外部代码的情况下,自由修改类的内部实现,因为外部代码无法直接访问private
成员变量。 - 灵活性:如果你将成员变量从一种数据类型更改为另一种,或者修改了其存储方式,只要不改变
public
接口,使用该类的外部代码就不需要修改。而如果成员变量是public
的,这样的修改会影响到依赖这些成员变量的外部代码,破坏封装性。
- 信息隐藏:将成员变量声明为
-
控制访问权限:
- 精确控制读写权限:通过将成员变量声明为
private
,你可以提供public
成员函数来精确控制对成员变量的读写权限。可以提供getter
函数用于读取成员变量的值,提供setter
函数用于修改成员变量的值,并且可以在这些函数中添加验证逻辑、日志记录、同步操作等。例如,对于一个private
的成员变量age
,可以这样定义getter
和setter
:
class Person { private:int age; public:int getAge() const { return age; }void setAge(int newAge) { if (newAge >= 0) { age = newAge; } else { // 处理错误,例如抛出异常或记录错误信息std::cerr << "Invalid age value" << std::endl; }} };
- 只读访问:如果只提供
getter
函数而不提供setter
函数,那么这个成员变量就是只读的,外部代码只能获取其值而不能修改。 - 读写分离:可以根据需要对不同的成员变量提供不同的读写权限,而不是将它们都暴露为
public
而无法控制其访问方式。
- 精确控制读写权限:通过将成员变量声明为
-
一致性和维护性:
- 接口一致性:通过成员函数访问成员变量可以让类的接口更加一致,并且可以为这些函数命名,使其更具描述性,让代码的可读性更强。
- 维护方便:如果需要在读取或修改成员变量时添加额外的操作,例如更新其他相关数据,或者对修改进行日志记录,使用
private
成员变量和public
成员函数的方式可以方便地在成员函数中添加这些操作,而无需修改外部代码。
三、对比其他访问权限:
-
public 成员变量:
- 当成员变量是
public
时,外部代码可以直接访问和修改它们,破坏了封装性。例如:
这样的代码难以维护,一旦需要对class BadClass { public:int value; }; BadClass obj; obj.value = 10; // 直接访问成员变量
value
进行修改,例如添加范围检查,就需要修改所有使用该成员变量的外部代码。
- 当成员变量是
-
protected 成员变量:
- 虽然
protected
比public
稍好,因为它至少限制了外部代码的访问,但仍然允许派生类直接访问,同样破坏了封装性。派生类可能会依赖这些成员变量,使得基类的修改变得困难。
- 虽然
四、总结:
- 为了实现良好的封装性、精确的访问控制、代码的一致性和易维护性,应该将成员变量声明为
private
,并使用public
成员函数来控制对它们的访问。这样可以提高代码的健壮性、可维护性和可扩展性,同时提供了更多的设计灵活性,是一种更好的软件设计实践。