Effective C++ rule 22.类成员变量尽量声明为private

来源:互联网 发布:iPad看视频软件 编辑:程序博客网 时间:2024/06/01 23:05

前言

Effective C++ 的rule 22在讨论类成员、函数的封装性,并给出了一些良性的忠告。

什么是封装

Data hiding is one of the important features of Object Oriented
Programming which allows preventing the functions of a program to
access directly the internal representation of a class type.

封装就是面向对象编程对类的成员数据进行隐藏,以防止其它函数直接去访问类的成员。那么封装的好处是什么呢?

  1. 保护语义完整性:这一点比较直观,就是说那些类内部的成员变量本来就不应该被类外直接访问到。
  2. 提供更加精准的控制。
  3. 为日后版本升级提供便利性。
    2,3点我们在下面的例子中给出解释。

如何衡量某个类成员的封装度

原文中提供了一种近似衡量类成员变量封装性的方法:数那些能够直接访问(使用->或逗号运算符)该变量的函数的个数N,封装性与N成反比。

比如说,某个public成员变量,它可以被任意多个函数直接访问到。那么public成员变量的封装性近似于0,这意味着,如果我们把这个public变量删除掉,所以类外使用了这个变量的代码都GG.

而如果是一个private的成员,那它的封装性就会好的多。因为类外没有直接访问private成员的函数。当这个变量删除后,外部代码修改的其实很少。

类的成员变量为什么private更好

private 成员的访问特性:

A private member of a class can only be accessed by the members and
friends of that class, regardless of whether the members are on the
same or different instances.

Private成员只能由本类的成员函数、本类的友员函数访问,而不管成员是否是在用一个类的实例里面。Private在检查访问控制符的时候是检查“类名:函数名”的。

当成员是private的时候,类外部想要去访问它就必须通过一个public函数了,这样我们就可以在函数里面加上一些更加精密的控制来约束调用者的访问行为。

举个例子:

#include<iostream>#include<string>using namespace std;class Person{public:    int age;    string name;    Person(int _age, string _name) :age(_age), name(_name)    {    }};int main(){    Person p(10, "Ada");    return 0;}

上面的age和name是public,因此任何地方都可以直接访问。
如果有类似的访问方式:
p.age=-1;
这种逻辑不合理的赋值也会赋值成功。为了避免使用者传入非法参数,我们可以先对使用者传入的进行判断,此时我们就可以把age声明为private变量,然后再使用public函数来对用户的参数进行合法性检查。
修改后的代码:

#include<iostream>#include<string>using namespace std;class Person{private:    int age;    string name;public:    Person(int _age, string _name) :age(_age), name(_name)    {    }    void Age_set(int _age)    {        if (_age >= 0)        {            age = _age;        }    }};int main(){    Person p(10, "Ada");    p.Age_set(-1);    return 0;}

这样即使有不合理的调用,也不会发生实际的赋值。这就是提供更加精确的访问控制。

此外,把变量声明为private还有一个好处,我们为外部提供private变量的public访问函数,当我们需要升级某些访问函数的时候,我们只要把函数内部的内容更新即可,类的使用者不受影响。

举个例子:

#include<iostream>#include<string>using namespace std;class Person{private:    int age;    string name;public:    Person(int _age, string _name) :age(_age), name(_name)    {    }    void Age_set(int _age)    {        if (_age >= 0)        {            age = _age;        }    }    int Age()    {        return age;    }};int main(){    Person p(10, "Ada");    p.Age_set(-1);    return 0;}

Person::Age()返回对象的age。假设我们需要返回的是Person的农历年龄,而不是age的值,那我们直接修改Person::Age()即可,调用Age()函数的代码块午休修改。这就是提供日后更新的便利性。

阅读全文
1 0
原创粉丝点击