水煮多态

原创 2005年05月24日 11:15:00

水是什么形状的?

乍一看这个问题似乎问得很没有道理,其实仔细想想,水正是自然界中“多态”的完美体现。不是么?用圆柱形容器装水,那么水就是圆柱形的;换用圆锥形容器盛之,水则又会成为圆锥形的了。在这个过程中,我们并不需要关心水是如何改变形状的,亦无需关心水在改变形状的过程中具体做了哪些事情;我们所要关心的,只是提供给它一个什么形状的容器,这就足够了。
OO(面向对象)中所谓的多态性,也正是这个道理。对于一个同名的方法(Water),我们在不同的情况(Container)下对其进行调用,那么它所完成的行为(Where_Am_I)也是不一样的。以下我将解说的,便是C++之中对于“多态”几种不同的实现形式。

函数的重载(Overload)

这儿是一个非常简单的函数max,它返回两个传入参数中较大的那一个。

int max( int a, int b )
{
    if ( a > b )
        return a;
    else
        return b;
}

相信这段代码的具体内容不用我解释了,是的,这是一段非常基本的代码。你可能会发现,这个max函数只适用于int类型的参数。那么,如果我同时还需要一个针对double类型的max,又该怎么办呢?
所幸C++语言本身提供了这一功能,它允许我们在定义函数的时候使用相同的名称——是为函数的重载。也就是说,我们可以继续定义一个double版本的max:

double max( double a, double b )
{
    if ( a > b )
        return a;
    else
        return b;
}

然后,在我们的代码中对这两个函数分别进行调用:

void f( void )
{
    int a = max( 1, 2 );
    double b = max( 1.5, 2.5 );
}

这样一来,我们无需关心调用的是哪个版本的max,编译器会自动根据我们给定的参数类型(int或double)挑选出最适当的max函数来进行调用。

模板(Template)

首先在这里说句题外话:“模板”的“模”应该如何发音?我发现,身边大多数的朋友喜欢发音为“mó”——当然我以前也是这么发音的。后来使用拼音输入法输入这个词语的时候,我才发现“模”在“模板”中应该读“mú”。字典上对“mú”音的解释为:使材料压制或浇灌成一定形状的工具。参考模板本身的特点,我觉得大抵也正是应该取“mú”音为佳。但是“mú板”又远远不及“mó板”读起来顺口,所以后来我但凡遇到这个词,一概发音为“template”。
言归正传。函数的重载的确为我们提供了很大的方便,我们不需要关心调用哪个函数,编译器会根据我们给定的参数类型挑选出最适当的函数进行调用。但是对于下面的情况,函数的重载就不是很适用了:

  ·函数体代码内容基本相同。
  ·需要为多个类型编写同样功能的函数。

也就是说,我们也许需要更多版本(int、double,甚至更多自定义类型,如复数complex之类)的max,但是它们的代码却无一例外的都是:

    if ( a > b )
        return a;
    else
        return b;

这样一来,我们需要做的事情就更倾向于一种体力劳动,而且,如是过多重复的工作也必然存在着错误的隐患。C++在这一方面,又为我们提供了一个解决方法,那就是模板。对于上面这众多版本且内容基本相同的max函数,我们只需要提供一个像下面这样函数模板即可:

template < typename T >
T max( const T& a, const T& b )
{
    if ( a > b )
        return a;
    else
        return b;
}

template是C++的关键字,表示它以下的代码块将使用模板。尖括号里面的内容称为模板参数,表示其中的T将在下面的代码模板中作为一种确定的类型使用。参数之所以使用const引用的形式,是为了避免遇到类对象的时候不必要的传值开销。在这个模板定义完毕之后,我们就可以像这样使用了:

void f( void )
{
    int a = max< int >( 1, 2 );
    double b = max< double >( 1.5, 2.5 );
}

对于这段代码,编译器会分别将int与double填充到函数模板中T所在的位置,也就是分别为max< int >和max< double >各自产生一份max函数的实体代码。这样一来,就达到了与函数重载一样的效果,但是程序员的工作量却是不可同日而语的。

虚函数(Virtual Function)

下面来以水为例,说说虚函数提供的多态表现形式。首先我们建立一个Water类,用来表示水。

class Water
{
public:
    virtual void Where_Am_I() = 0;
};

正如单独讨论水的形状没有意义一样,我们在这里当然也不能允许Water类的实例化,所以成员函数Where_Am_I被定义为了纯虚函数。下面,我们来分别定义水(Water)在瓶子(Bottle)、玻璃杯(Glass)以及湖泊(Lake)中的三种不同情况:

class Water_In_Bottle : public Water
{
public:
    virtual void Where_Am_I()
    {
        cout << "Now I'm in a bottle." << endl;
    }
};

class Water_In_Glass : public Water
{
public:
    virtual void Where_Am_I()
    {
        cout << "Now I'm in a glass." << endl;
    }
};

class Water_In_Lake : public Water
{
public:
    virtual void Where_Am_I()
    {
        cout << "Now I'm in a lake." << endl;
    }
};

这三者分别实现了成员函数Where_Am_I。然后,多态性的实现就可以通过一个指向Water的指针来完成:

void f( void )
{
    Water_In_Bottle a;
    Water_In_Glass  b;
    Water_In_Lake   c;

    Water *pWater[3];
    pWater[0] = &a;
    pWater[1] = &b;
    pWater[2] = &c;

    for ( int i = 0; i < 3; i++ )
    {
        pWater[i]->Where_Am_I();
    }
}

这样,程序的运行结果是:

Now I'm in a bottle.
Now I'm in a glass.
Now I'm in a lake.

好了,如你所见,我们并不需要关心pWater指向的是哪一种水,而只需要通过这个指针进行相同的调用工作,水本身就可以根据自身的所在来选择相应的行为。虚函数的多态性是非常有用的,尤其是在使用C++进行Windows程序设计的时候。考虑那些不同的窗口针对用户的相同行为而能够做出不同反应,也正是由于相应的消息响应虚函数的具体实现不同,方能达到这样的效果。

水煮多态,暂且煮到这里。这里所谈及的仅仅是C++对于多态的表现形式,而并未对文中三种技术(重载、模板、虚函数)的具体内容进行过多的解说——毕竟稍微一深入就难免会对某些技术细节进行大篇幅追究,譬如说到重载难免就会说到参数的匹配,说到模板又难免与泛型进行挂钩,到了虚函数又不能不提一下VTable的东西……在这里我一概全免,因为我的目的也就是希望通过上面几个简单的例子让诸位看官能对OO本身的多态有一个感性的认识,感谢您们的阅读。

水煮多态

水是什么形状的?乍一看这个问题似乎问得很没有道理,其实仔细想想,水正是自然界中“多态”的完美体现。不是么?用圆柱形容器装水,那么水就是圆柱形的;换用圆锥形容器盛之,水则又会成为圆锥形的了。在这个过程中...
  • nicholasmaxwell
  • nicholasmaxwell
  • 2007年05月16日 22:58
  • 571

温水煮青蛙的安逸感

在知乎上看到这样一段话: “渣学校意味着渣教学,渣教学意味着渣学历,渣学历意味着渣就业,就算以后考了研究生,也有可能因为你的第一学历不过关而被拒之门外。” 真是这样? 二本大学的环境...
  • tzs_1041218129
  • tzs_1041218129
  • 2016年04月04日 21:43
  • 845

煮玉米加盐会更加甜

水煮玉米也有技巧。是不是常常觉得外面卖的水煮玉米又香又甜,但是自己在家做的就显得有点硬有点干,甜度也不够?其实可能只需要一小步的改善,你在家也可以煮出甜丝丝的玉米。 煮玉米不要把皮剥得干干净净 煮...
  • sdgdt
  • sdgdt
  • 2016年03月10日 14:43
  • 113

水煮互联网创业,互联网创业的盲区

1 鞋厂理论:世界上有无数家鞋厂,制造着各自的鞋子,销售给各自的客户。在网络上,当某个生意已经有人在做的时候,就想想皮鞋理论,你会发现:在大多数情况下,即使有很多人在做鞋子,也并不意味着你就不能再去做...
  • java2000_net
  • java2000_net
  • 2009年05月06日 17:20
  • 2098

水煮三国:第一章:创业时代的七堂必修课

创业时代的七堂必修课    我们无法用眼睛和手指从一堆沙子中间找到铁屑,就像我们很难从茫茫人海中找到我们的顾客一样。然而,有一种工具能够帮助我们迅速地从沙子中间找到铁屑…………第一课  命运是一只沦落...
  • cxin917
  • cxin917
  • 2007年11月12日 23:36
  • 547

清闲的工作与温水煮青蛙;-)

今天和朋友闲谈,聊到了温水煮青蛙的问题。朋友说,现在的单位,工作虽然清闲,但是感觉就像温水煮青蛙,觉得没有前途,待的时间长了,也就走不了了。想来如是,朋友的工作说起来确实是满轻松的,做软件外包测试,负...
  • againstwar
  • againstwar
  • 2007年12月23日 21:29
  • 3734

近期阅读书籍列表

最近比较悠闲,也整理一下最近一年看过的书籍和以后准备去阅读的书,由于前几年做项目都属于赶鸭子上架,做项目之前还没来得及系统的去学习(主要原因还是没有养成看书的习惯),由于本人不太喜欢看电子书籍,所以大...
  • sheshou2
  • sheshou2
  • 2010年11月18日 11:56
  • 942

水煮三国第二章:能把梳子卖给和尚吗?

信而安之,阴以图也。此笑里藏刀之计,公岂可不察耶? 求职遭遇奇妙陷阱把梳子卖给和尚吕布卖出了999把梳子天机终于被泄露了为恶者必灭 ...
  • cxin917
  • cxin917
  • 2007年11月12日 23:55
  • 601

人生的思考——温水中被煮熟的程序员

很多时候我们不去行动,并不是我们不想去行动,而是我们不知道该从什么地方开始! 怕什么真理无穷,进一步有一步的欢喜 怕什么路途遥远。走一步有一步的风景...
  • u010648555
  • u010648555
  • 2017年02月14日 17:52
  • 503

[转]水煮多态--对多态讲的很形象

水是什么形状的?乍一看这个问题似乎问得很没有道理,其实仔细想想,水正是自然界中“多态”的完美体现。不是么?用圆柱形容器装水,那么水就是圆柱形的;换用圆锥形 容器盛之,水则又会成为圆锥形的了。在这个过程...
  • shuni9
  • shuni9
  • 2008年04月16日 14:57
  • 236
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:水煮多态
举报原因:
原因补充:

(最多只允许输入30个字)