文档介绍:第二十三章  类/class (一) 封装
从“我吃饭”开始
从“结构”到“类”
类的成员数据与成员函数
  成员数据初始化的疑问
  成员函数的实现
封装
  私有成员/private member
  保护成员/protected member
  公有成员/public member
  “封装”的作用
作业
从“我吃饭”开始
我吃饭……
其中,“我”是一个变量,“我”的类型是“人类”;
“吃”是一个函数。
“饭”也是一个变量,它的类型是“食物”。这里用于做函数“吃”的参数。
“我吃饭”!这是一种面向对象的思想的表达。其中的对象是“我”。以我为中心。我因为是人类,所以具备“吃”这种能力。如果说“桌子吃饭”,那么编译器会报错,因为桌子属于家具类,而家具不提供“吃”的函数。
C++是一种具备面向对象能力的编程语言,所以,用C++来表达“我吃饭”这样一件事时,它的代码风格贴近这种人类的自然语言,即:(饭);“我”是一个对象,“吃”是“我”所属对象(人类)的一个函数,而“饭”是函数参数。
换成C语言,因为它不具备面向对象的设计思想,所以,它只能说成:“吃(我,饭)”。“吃”是函数,“我”和“饭”是两个参数。没有人规则一定要把“我”作为第一个参数,你尽可写成“吃(饭,我)”。二者比较,面向对象的最基本的好处或许您已经有所体会:自然,从而不容易出错。
从“结构”到“类”
上一章我们学习了结构(struct)。(强烈建议你暂时放下新课程,重温一下struct)。
结构让我们具备了把多种相同或不同的类型,组成一种新类型的能力。
比如上一章讲的“宝宝/BaoBao”这一结构,它的组合为:
struct BaoBao
{
    char xingMing[11]; //用字符数组,来存储姓名
    int shenGao; //身高,整型
    float tiZhong; //体重,实型
};
通过struct,我们通过将简单数据类型(int,float,bool……)或简单数据类型的数组、指针,组合成一个新的数据类型。由此,我们在用程序表达复杂的现实世界时,更接近了一步。但是别忘了,我们说过世界是由“数据”和“动作”组成的。光能定义出各种数据类型,还只是编程世界的一半。你可能会说,我们有函数啊,函数不是可以表达“动作”?
没错,比如说,宝宝肯定有“吃”的动作,所以我来声明一个“吃”的函数。为了直观,我们的函数命名为“Chi”。并且我们假充有一种数据类型叫“饭”,同样用拼音Fan表示,首字母大写,而小写的fan用来做形参。
void Chi(Fan fan);
乍一看,感觉这个函数这样声明也就对了。“吃饭”函数嘛,有“吃”又有“饭”……可仔细一想,谁吃饭啊?这个光有吃的动作和吃的东西,和我们前面的“宝宝”数据类型有何关系?所以,显然不够,需要再加一个参数,用于传一个“要吃饭”的宝宝进去。因此函数变成:
void Chi(BaoBao bb, Fan fan);
得,“吃我饭”的表达出来了。过程化的编程,其设计重在关心“过程”,比如:“如何吃”,但这个世界要求我们完整地关心“谁?如何吃?吃什么?”。事实上,同一样一个“吃”,宝宝吃的动作,和一个大男人吃的动作;或者,吃饭还是吃奶的动作?怕是完全不一样。如果真写,就不得不写很多版本的“吃”这一函数:
假设用DNR表大男人(晕,好像大女人也可以?):
void DNRChi(DNR dnr, PingGuo pg); //吃函数版本一:大男人吃苹果
void DNRChi(DNR dnr,Fan fan); //吃函数版本二:大男人吃饭
void BaoBaoChi(BaoBao bb, Nai nai); //吃函数版本三:宝宝吃奶
void BaoBaoChi(BaoBao bb, Fan fan); //吃函数版本四:宝宝吃饭
......
这样的函数还可以有很多。函数多或许并没有错,必竟所要表达事物本来就复杂。然而问题是我们如何去理解,区分,记忆这些函数呢?仅靠函数名和函数参数的不同吗?在超市付款时,看过收款员拉开过放钱的小抽屉吗?拉开一看,都是钱,但10元的5元,100元的及硬币分门别类地放好……聪明的你一定会提出:如果能把函数也归类就好了……这就有了“类”,英文称为:class。
请仔细看,下面示例的class定义里,加入了一个函数:
c