本文发表在 rolia.net 枫下论坛OO的主要特征是什么?对了,就是封装、继承和多态这三大特征。
首先从封装讲起,如果我们没有了public, private, protected这三个关键字,我可以合理地假设所有成员的属性应该是public的(我想你不会写一段代码唯一的功能就是自娱自乐)。那么这个时候,所有成员都是公开的,也就是说你所做的只是包装(pack)而不是封装(encapuslate)。这时候要求你提供一个类的实现,你除了接口说明,还必须附上一纸申明:"严禁使用func1、func2、func3....违者罚款xxx,跑圈xxx,引体向上xxx,腹部绕杠xxx......."
接着说继承。你是否理解共有继承、保护继承和私有继承的关系?简单讲,共有继承是个"是一个"的关系。保护继承和私有继承是一个"有一个"的关系。两者概念是不同的。这样我举个例子来说明吧。就那OO里面最常说事的汽车来讲。我是一个汽车发动机厂家,设计了一个基本型的发动机EngineBasic。然后在此基础上设计外销的发动机EngineA。此时,我们要用公有继承:EngineA: public EngineBasic。因为EngineBasic的所有特性(接口)我们同样实现在EngineA上,提供给用户使用。
现在你变成一个汽车厂家,你的任务是利用购买来的EngineA设计一个动力模块PowerModule。这时候我想你并不希望你这个模块的使用者绕过你的模块直接访问EngineA。但是显然你模块中的部件必需访问EngineA,那毕竟是你的核心部件啊。所以EngineA的接口应当只是对PowerModule内部可见,外部使用的人必须通过你的PowerModule才可以改变EngineA的状态。同时考虑到你的模块;可能使用在卡车上,也可能使用在Van上,也可能使用在小车上。也就是说你的PowerModule可能会有一些子型号PowerModuleA,PowerModuleB。所以你选用了保护继承:PowerModule:protected EngineA.
现在你设计了一款汽车姑且命名为QSBC。(气死奔驰)。你准备使用上述你设计的动力模块的某一型号PowerModuleA。显然,你作为汽车设计者,你希望你的用户自能通过挂档、油门或刹车控制你的动力模块,你不希望你的用户不踩油门就直接发指令给动力模块加速。所以PowerModuleA的接口应该只能通过汽车内部访问。同时,你也不希望你的用户买了你的车自己进行改装,改成ASBC(爱死奔驰)。这里,你就使用了私有继承QSBC:private PowerModuleA。
当然讲到这里,你会说,没有保护继承和私有继承,我可以使用类的组合啊,那也是表示"有一个"的关系。这里就涉及到了多态。是的,你使用类的组合可以写成:
QSBC mycar {
:
PowerModuleA core;
:
}
这也表示mycar "有一个"PowerModuleA 的关系。但是这一是破坏了封装。买了QSBC的人可以不踩油门,直接调用mycar.core.accelerate来加速。二是破坏了多态。显然,我调用mycar.accelerate和调用mycar.core.accelerate是截然不同的两个方法:"同名的不同方法有不同的行为",并不是"同一个方法在不同类中的不同行为"。如果你一定要定义这也是多态,那么建议你重新设计一个全新理念的OO语言。
好了,我想这大概足够说明public, private, protected这三个关键字的作用了。
另外,有一些常用的应用如命名的构造函数"Named Constructor Idiom"、singleton类等,都要求 private或protected。你自己可以搜搜。更多精彩文章及讨论,请光临枫下论坛 rolia.net
首先从封装讲起,如果我们没有了public, private, protected这三个关键字,我可以合理地假设所有成员的属性应该是public的(我想你不会写一段代码唯一的功能就是自娱自乐)。那么这个时候,所有成员都是公开的,也就是说你所做的只是包装(pack)而不是封装(encapuslate)。这时候要求你提供一个类的实现,你除了接口说明,还必须附上一纸申明:"严禁使用func1、func2、func3....违者罚款xxx,跑圈xxx,引体向上xxx,腹部绕杠xxx......."
接着说继承。你是否理解共有继承、保护继承和私有继承的关系?简单讲,共有继承是个"是一个"的关系。保护继承和私有继承是一个"有一个"的关系。两者概念是不同的。这样我举个例子来说明吧。就那OO里面最常说事的汽车来讲。我是一个汽车发动机厂家,设计了一个基本型的发动机EngineBasic。然后在此基础上设计外销的发动机EngineA。此时,我们要用公有继承:EngineA: public EngineBasic。因为EngineBasic的所有特性(接口)我们同样实现在EngineA上,提供给用户使用。
现在你变成一个汽车厂家,你的任务是利用购买来的EngineA设计一个动力模块PowerModule。这时候我想你并不希望你这个模块的使用者绕过你的模块直接访问EngineA。但是显然你模块中的部件必需访问EngineA,那毕竟是你的核心部件啊。所以EngineA的接口应当只是对PowerModule内部可见,外部使用的人必须通过你的PowerModule才可以改变EngineA的状态。同时考虑到你的模块;可能使用在卡车上,也可能使用在Van上,也可能使用在小车上。也就是说你的PowerModule可能会有一些子型号PowerModuleA,PowerModuleB。所以你选用了保护继承:PowerModule:protected EngineA.
现在你设计了一款汽车姑且命名为QSBC。(气死奔驰)。你准备使用上述你设计的动力模块的某一型号PowerModuleA。显然,你作为汽车设计者,你希望你的用户自能通过挂档、油门或刹车控制你的动力模块,你不希望你的用户不踩油门就直接发指令给动力模块加速。所以PowerModuleA的接口应该只能通过汽车内部访问。同时,你也不希望你的用户买了你的车自己进行改装,改成ASBC(爱死奔驰)。这里,你就使用了私有继承QSBC:private PowerModuleA。
当然讲到这里,你会说,没有保护继承和私有继承,我可以使用类的组合啊,那也是表示"有一个"的关系。这里就涉及到了多态。是的,你使用类的组合可以写成:
QSBC mycar {
:
PowerModuleA core;
:
}
这也表示mycar "有一个"PowerModuleA 的关系。但是这一是破坏了封装。买了QSBC的人可以不踩油门,直接调用mycar.core.accelerate来加速。二是破坏了多态。显然,我调用mycar.accelerate和调用mycar.core.accelerate是截然不同的两个方法:"同名的不同方法有不同的行为",并不是"同一个方法在不同类中的不同行为"。如果你一定要定义这也是多态,那么建议你重新设计一个全新理念的OO语言。
好了,我想这大概足够说明public, private, protected这三个关键字的作用了。
另外,有一些常用的应用如命名的构造函数"Named Constructor Idiom"、singleton类等,都要求 private或protected。你自己可以搜搜。更多精彩文章及讨论,请光临枫下论坛 rolia.net