封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫接口。(数据安全机制)
有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
继承+多态:继承和多态必须一起说。一旦割裂,就说明理解上已经误入歧途了。
先说继承:继承同时具有两种含义:其一是继承基类的方法,并做出自己的改变和/或扩展——号称解决了代码重用问题;其二是声明某个子类兼容于某基类(或者说,接口上完全兼容于基类),外部调用者可无需关注其差别(内部机制会自动把请求派发[dispatch]到合适的逻辑)。(继承就是一种特殊的代码复用功能)
再说多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。(简单的理解 多态 == 覆盖和调用虚函数 )(多态比较复杂,各种骚操作都要用多态实现)
很显然,多态实际上是依附于继承的两种含义的:“改变”和“扩展”本身就意味着必须有机制去自动选用你改变/扩展过的版本,故无多态,则两种含义就不可能实现。
所以,多态实质上是继承的实现细节;那么让多态与封装、继承这两个概念并列,显然是不符合逻辑的。不假思索的就把它们当作可并列概念使用的人,显然是从一开始就被误导了——正是这种误导,使得大多数人把注意力过多集中在多态这个战术层面的问题上,甚至达到近乎恶意利用的程度;同时却忽略了战略层面的问题,这就致使软件很容易被他们设计成一滩稀屎(后面会详细谈论这个)。


class Fish // base class{// ... Fish's members};class Carp:public Fish// derived class{// ... Carp's members};
鱼类世界呈现的一种简单的继承层次结构
#include <iostream>#include <string>using namespace std;class Fish{public:bool is_fresh_water_fish;void swim(){if (is_fresh_water_fish){cout << "Swims in lake" << endl;}else{cout << "Swims in sea" << endl;}}};class Tuna: public Fish{public:Tuna(){is_fresh_water_fish = false;}};class Carp: public Fish{public:Carp(){is_fresh_water_fish = true;}};int main(){Carp my_lunch;Tuna my_dinner;cout << "About my food: " << endl;cout << "Lunch: ";my_lunch.swim();cout << "Dinner: ";my_dinner.swim();return 0;}
基类初始化—向基类传递参数
如果基类包含重载的构造函数,需要在实例化时给它提供实参,该如何办呢?创建派生对象时将 如何实例化这样的基类?方法是使用初始化列表,并通过派生类的构造函数调用合适的基类构造函数
class Base{public: Base(int someNumber) // overloaded constructor{// Use someNumber}};Class Derived: public Base {public: Derived(): Base(25) // instantiate Base with argument 25{// derived class constructor code}};
对 Fish 类来说,这种机制很有用。通过给 Fish 的构造函数提供一个布尔输入参数,以初始化 Fish::isFreshWaterFish,可强制每个派生类都指出它是淡水鱼还是海水鱼
#include <iostream>#include <string>using namespace std;class Fish{protected:bool is_fresh_water_fish;public:Fish(bool is_fresh_water): is_fresh_water_fish(is_fresh_water){}void swim(){if (is_fresh_water_fish){cout << "Swims in lake" << endl;}else{cout << "Swims in sea" << endl;}}};class Tuna: public Fish{public:Tuna():Fish(false) {}};class Carp: public Fish{public:Carp():Fish(true){}};int main(){Carp my_lunch;Tuna my_dinner;cout << "About my food: " << endl;cout << "Lunch: ";my_lunch.swim();cout << "Dinner: ";my_dinner.swim();return 0;}
在派生类中覆盖基类的方法
如果派生类实现了从基类继承的函数,且返回值和特征标相同,就相当于覆盖了基类的这个方法, 如下面的代码所示:
class Base{public:void DoSomething(){// implementation code… Does something}};class Derived:public Base{public:void DoSomething(){// implementation code… Does something else}};
因此,如果使用 Derived 类的实例调用方法 DoSomething( ),调用的将不是 Base 类中的这个方法。如果 Tuna 和 Carp 类实现了自己的 Swim( )方法,则在程序清单 10.3 的 main( )中下述代码将调用Tuna::Swim( )的实现,这相当于覆盖了基类 Fish 的方法 Swim( ):
在派生类中调用基类的方法
通常,Fish::Swim( )包含适用于所有鱼类(包括金枪鱼和鲤鱼)的通用实现。如果要在 Tuna::Swim( ) 和 Carp::Swim( )的实现中重用 Fish::Swim( )的通用实现,可使用作用域解析运算符(::),如下面的代码所示:
class Carp: public Fish{public:Carp(): Fish(true) {}void Swim(){cout << "Carp swims real slow" << endl;Fish::Swim(); // invoke base class function using operator::}};
在基类方法和 main( )中,使用作用域解析运算符(::)来调用基类方法
#include <iostream>#include <string>using namespace std;class Fish{private:bool is_fresh_water_fish;public:Fish(bool is_fresh_water): is_fresh_water_fish(is_fresh_water){}void swim(){if (is_fresh_water_fish){cout << "Swims in lake" << endl;}else{cout << "Swims in sea" << endl;}}};class Tuna: public Fish{public:Tuna():Fish(false) {}void swim(){cout << "Tuna swims real fast, ";}};class Carp: public Fish{public:Carp():Fish(true){}void swim(){cout << "Carp swims real slow, ";Fish::swim();}};int main(){Carp my_lunch;Tuna my_dinner;cout << "About my food: " << endl;cout << "Lunch: ";my_lunch.swim();cout << "Dinner: ";my_dinner.swim();my_dinner.Fish::swim();return 0;}

