标签:
类的封装可以理解为:
电视机,我们会操作就行了,我才不关心他是怎么实现的呢?内部构造那是生产和设计人员的事情!
比如人类,有手有脚,有眼睛(人类的属性),会跑会吃(人类的行为)我们通过封装把属性和行为(方法)组装起来,形成一个类(人类),我们可让某个人(人类的一个对象)吃饭,跑步,(调用方法),但我们不能让某个人长三只眼睛(就是说我们不应该去直接操作属性),而跑步要用到腿(属性),腿的长短可能决定了跑的快慢(属性影响了方法).封装也确实实现了重用,我们只要为人类创建一个跑方法,以后我们要让张三跑那么就创建一个对象并给他个名子叫张三,然后让他跑.
类封装的好处:
第一:重用;
我们可以在封装方法后,对象可以多次调用方法,而不用每次都去写该方法。
第二:不必关心具体的实现;
程序员只管直接使用。
第三:面向对象三大特征之一,
模块化,可以很好的区分及应用。类的封装时面向对象的基础概念风格,就是把每个对象的东西装在一起,如果像某些人说的把说有对象方法,都放在一个箱子里的话,那么将很难团队合作分工,改需求时也很难改。
第四,具有安全性
封装好后,我们并不知道类中是怎么实现的。只是简单的使用了该方法。
第五:
封装后可以修改类的内部实现,而无需修改使用了该类的客户代码(即坏了容易替换,不影响全局)
第六:
封装后可以对成员进行更精确的控制,例如将某个成员设置为只读的。
验证第五、六点
以下验证转自: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
可见,封装后我们可以对成员进行更精确的控制,这样可以避免一些错误。
标签:
原文地址:http://www.cnblogs.com/ting1025/p/4839057.html