封装是一项低层次的元素组合起来形成新的、高层次的实体技术。类的设计者讲一个类型的数据成员、函数成员、类类型的成员封装到一起,形成一种新的抽象类型或者具体类型。函数(类外称接口)是封装的一种形式:函数所执行的细节被封装在函数这个本身的实体中。被封装的元素隐藏了他们的实现细节——可以调用但是不能访问他所执行的具体细节,实现的具体语句。
类是一个封装的实体。并且隐藏了实现该类类型的成员。
在C++中,标准库类型有很多封装好的类型如:vector、list、map、set等,这些类型同时兼具有数据抽象与封装的特性,对于类的使用者而言,他是抽象的,因为使用者只需要考虑类接口能够帮助他们完成什么功能?不同的接口能够执行什么动作?并且也是封装的,因为我们无法了解该类型是如何具体实现的,实现的细节是什么?如:
//初始化类vector
int ages[] = {20, 23, 29, 30};
vector<int> vAge(ages, ages+3);
//使用者只需要了解类接口能够完成什么事情
//vector类型的front()返回类型vector中的第一个元素
std::cout << vAge.front();
//at(index)接口返回类型中第index个元素
std::cout << vAge.at(1);
数据抽象与封装的实施手段——访问权限标号
在C++中,使用访问权限标号来定义类的抽象数据接口和实施封装。
一个类可以没有访问权限标号(C++中,class的默认访问权限标号是private,而struct类型的默认访问权限标号是public),也可以包含多个访问权限标号。
如:
//设计了一个类Person,拥有一个接口返回Person的名字
class Person{
public:
Person();
private:
string name;
protected:
int age;
public:
string getName() const;
};
string Person::getName() const{
return name;
}
Person::Person():name("Josin"), age(22){
}
关于访问权限标号public、protected、private的作用范围见我的上一篇博文。
类的
具体类型、
抽象类型
具体类型是类的设计者在设计类的同时也进行了类的接口的实现,抽象类型是指类的设计者只进行了接口的定义而没有进行接口的实现。
如:
class Cooker{
public:
//接口一
void cook();
//接口二
void gruel();
//接口三
void soup();
};
具体类型:
class Cooker{
public:
//接口一
void cook(){
for (int i = 0; i < 10; i++)
{
std::cout << i << std::endl;
}
}
//接口二
void gruel(){
int i = 0;
while (true)
{
if (i = 100)
{
return;
}
std::cout << i << std::endl;
}
}
//接口三
void soup(int i){
if (i == 1000)
{
return;
}
soup(i+1);
}
};
抽象类型与具体类型:抽象类型的作用是什么?在日常的软件开发中,时常会碰到一些问题如:不同品牌的电吹风都有一些相似的功能、不同品牌的电饭锅都有一些相似的功能。这里这些”相似的“就是我们抽象类型的作用了,比如说:我们可以在我们的程序中定义一个抽象类型Cooker如上所示,并且定义两个具体类型:Media、Philip来形容两中具体的电饭锅:
class Media : public Cooker{
public:
void cook(){
//执行各自的煮饭功能
}
void gruel(){
//执行各自的熬粥功能
}
void soup(){
//执行各自的熬汤功能
}
};
class Philip : public Cooker{
public:
void cook(){
//执行Philips的煮饭功能
}
void gruel(){
//执行各自的熬粥功能
}
void soup(){
//执行各自的熬汤功能
}
};
因为不同的品牌具体的煮饭、熬汤的过程有不同,所以只要针对不同的品牌设置不同的步骤就可以了。