类的封装

类的封装可以理解为:

电视机,我们会操作就行了,我才不关心他是怎么实现的呢?内部构造那是生产和设计人员的事情!

比如人类,有手有脚,有眼睛(人类的属性),会跑会吃(人类的行为)我们通过封装把属性和行为(方法)组装起来,形成一个类(人类),我们可让某个人(人类的一个对象)吃饭,跑步,(调用方法),但我们不能让某个人长三只眼睛(就是说我们不应该去直接操作属性),而跑步要用到腿(属性),腿的长短可能决定了跑的快慢(属性影响了方法).封装也确实实现了重用,我们只要为人类创建一个跑方法,以后我们要让张三跑那么就创建一个对象并给他个名子叫张三,然后让他跑.

类封装的好处:

第一:重用;

我们可以在封装方法后,对象可以多次调用方法,而不用每次都去写该方法。

第二:不必关心具体的实现;

程序员只管直接使用。

第三:面向对象三大特征之一,

模块化,可以很好的区分及应用。类的封装时面向对象的基础概念风格,就是把每个对象的东西装在一起,如果像某些人说的把说有对象方法,都放在一个箱子里的话,那么将很难团队合作分工,改需求时也很难改。

第四,具有安全性

封装好后,我们并不知道类中是怎么实现的。只是简单的使用了该方法。

第五:

封装后可以修改类的内部实现,而无需修改使用了该类的客户代码(即坏了容易替换,不影响全局)

第六:

封装后可以对成员进行更精确的控制,例如将某个成员设置为只读的。

 

验证第五、六点

以下验证转自:http://blog.csdn.net/selina6874/article/details/8136758

以前总是体会不到封装的好处。看书或者向他人咨询时,得到的答案都是:封装后可以修改类的内部实现,而无需修改使用了该类的客户代码;封装后可以对成员进行更精确的控制,例如将某个成员设置为只读的。但是这些都是理论,没有切身感悟。

最近在修改代码时遇到了一个相关问题,对封装的好处有了初步的体会。

假设现在有这样一个类:

 

class Man  

{  

public:  

  string name;  

  string age;  

};  

 

它拥有两个public的成员。当使用它的时候,会像这样:

 

Man man;  

man.name = “Hotdog”;  

man.age = ”22”;  

这样一来,我们若是修改了Man类的实现,例如需要把age成员改为int类型,那么Man类现在看起来就会是这样:

 

 

class Man  

{  

public:  

  string name;  

  int age;  //age成员改为int类型  

 };  

 

而相应的使用它的地方也需要修改,修改后类似这样:

 

Man man;  

man.name = “Hotdog”;  

man.age = 22;  

当然,在这个例子中使用Man类的地方只有一处,改动起来并不费时。而对于大型项目中的关键类,使用它的地方可能有成千上万处,将每处一一修改,是一个很大的工作量。

现在我们重新设计Man类,以求在修改类的内部实现时,无需修改客户代码。重新设计后的Man类将是这样:

 

class Man  

{  

public:  

  string getName() { return name; }  

  void setName(string n) { name = n; }  

  string getAge() { return age; }  

  void setAge(string a) { age = a; }  

private:  

  string name;  

  string age;  

};  

现在它依然拥有两个成员变量,name和age,不过现在这两个成员变量都是private的。它还拥有public的成员函数,用来获取和设置成员变量的值。现在,我们会像这样使用Man类:

 

Man man;  

man.setName(“Hotdog”);  

man.setAge(“22”);  

如果想把age成员修改为int类型,会像这样:

 

class Man  

{  

public:  

  string getName() { return name; }  

  void setName(string n) { name = n; }  

  string getAge() { stringstream ss; ss << age; return ss.str(); }  

  void setAge(string a) { stringstream(a) >> age; }  

private:  

  string name;  

  int age;  //age成员改为int类型  

};  

这次只修改了getAge()和setAge()的内部实现,而没有修改接口,因此无需修改使用Man类的地方。

至此,第一个问题算是告一段落,封装确实可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码

再用这个例子来看一看第二个问题:封装后可以对成员进行更精确的控制。Man类最初看起来是这样的:

 

class Man  

{  

public:  

  string name;  

  int age;  

 };  

使用起来会是这样:

 

Man man;  

man.name = “Hotdog”;  

man.age = 22;  

当然了,这是“正常的”使用,但是客户有时候会不那么“正常”,有时候会粗心大意(特别是打瞌睡的时候),会错误地写出这样的代码:

 

 

man.age = 222;  //喔,不经意间多打了一个2  

而Man类发现不了这样的问题,还是忠诚地接受了一个年龄为222的Man。这似乎看起来有些可笑。其实这个可笑的问题可以简单地避免——把成员变量封装起来:

 

class Man  

{  

public:  

  string getName() { return name; }  

  void setName(string n) { name = n; }  

  int getAge() { return age; }  

  void setAge(int a)   

  {   

    if (age > 0 && age < 150)   

      age = a;   

    else  

      cout << “error age input.” << endl;  

  }  

private:  

  string name;  

  int age;  

};  

现在,如果写出了

 

man.age = 222;  

这样的糊涂代码,程序就会打印出一条警告信息“errorage input.”。

另外,封装性还可以用于实现只读变量,例如:

 

class Man  

{  

public:  

  Man(string n, int a) { name = n; age = a; }  

  string getName() { return name; }  

  int getAge() { return age; }  

  void setAge(int a) { age = a; }  

private:  

string name;  

  int age;  

};  

这样的话,当构造出一个Man对象后,name就成了只读的,因为这里只提供了

 

 

getName(),而没有提供setName()。  

Man man(“Hotdog”, 22);  

man.setName(“Cooldog”); //Error! No such member function  

man.setAge(23);     //OK  

 

可见,封装后我们可以对成员进行更精确的控制,这样可以避免一些错误。

 

posted @ 2015-09-25 18:31  婷汀雨俐  阅读(130)  评论(0编辑  收藏  举报