C/C++编程:模板的多态

1059 篇文章 278 订阅

多态是一种能够令单一的泛型标记关联不同特定行为的能力。对于面向对象的程序设计而言,多态是一块基石。在C++中,这块基石主要是通过继承和虚函数实现的。由于这两个机制都是(至少一部分)在运行期进行处理的,因此我们把这种多态称为动多态(一般讲的多态就是这种多态)。然而,模板也允许我们使用单一的泛型标记来关联不同的特定行为,但是这种关联是在编译期进行处理的。因此我们把这种叫做静多态

动多态

  • 动多态是通过继承和虚函数实现的
  • 动多态的设计思想:对于几个相关对象的类型,确定它们之间的一个共同功能集;然后在基类中,把这些共同的功能声明为多个虚函数接口

一个典型例子:一个用于管理几何形状,并且能够以某种方式进行修改的应用程序。设计实现:一个声明一些适用于其他所有几何对象的公共操作和属性的抽象基类Geobj,一些派生自Geobj的具体几何对象的类

在这里插入图片描述

//poly/coord.hpp

#include <cstdlib>

class Coord {
  private:
    int x, y;
  public:
    Coord (int i1, int i2) : x(i1), y(i2) {
    }
    friend Coord operator- (Coord const& c1, Coord const& c2) {
        return Coord(c1.x-c2.x, c1.y-c2.y);
    }
    Coord abs() {
        return Coord(std::abs(x),std::abs(y));
    }
};
//poly/dynahier.hpp

#include "coord.hpp"

//针对几何对象的公共抽象基类GeoObj 
class GeoObj {
  public:
    // 画出几何对象
    virtual void draw() const = 0;
    // 返回几何对象的重心
    virtual Coord center_of_gravity() const = 0;
    //...
};

// 具体的几何对象类GeoObj 
// - 派生自 GeoObj
class Circle : public GeoObj {
  public:
    virtual void draw() const;
    virtual Coord center_of_gravity() const;
    //...
};

// 具体的几何对象类GeoObj 
// - 派生自 GeoObj
class Line : public GeoObj {
  public:
    virtual void draw() const;
    virtual Coord center_of_gravity() const;
    //...
};
//...

生成了具体对象之后,客户端代码就可以通过指向基类的引用或者指针来操作这些对象,并且能够通过这些引用或者指针来实现虚函数的调度机制。也就是说,利用一个指向基类(子对象)的指针或者引用来调用虚成员函数,实际上可以调用(指针或者引用实际上所代表的)具体类对象的成员

#include "dynahier.hpp"
#include <vector>

// 画任意一个GeoObj
void myDraw (GeoObj const& obj)
{
    obj.draw();            // 根据对象的类型调用相应的draw()
}

//计算两个GeoObjs对象之间中心的距离
Coord distance (GeoObj const& x1, GeoObj const& x2)
{
    Coord c = x1.center_of_gravity() - x2.center_of_gravity();
    return c.abs();        // 返回坐标的绝对值
}

// draw属于异类对象的GeoObjs对象
void drawElems (std::vector<GeoObj*> const& elems)
{
    for (unsigned i=0; i<elems.size(); ++i) {
        elems[i]->draw();  // 根据对象的类型调用draw()
    }
}

int main()
{
    Line l;
    Circle c, c1, c2;

    myDraw(l);            // myDraw(GeoObj&) => Line::draw()
    myDraw(c);            // myDraw(GeoObj&) => Circle::draw()

    distance(c1,c2);      // distance(GeoObj&,GeoObj&)
    distance(l,c);        // distance(GeoObj&,GeoObj&)

    std::vector<GeoObj*> coll;  //元素类型互异的集合
    coll.push_back(&l);         // insert line
    coll.push_back(&c);         // insert circle
    drawElems(coll);            // 画不同种类的 GeoObjs
}

对于动多态而言,最引人注目的特性或许是处理异类容器的能力

静多态

模板也能用来实现多态。然而,这种多态并不依赖于在基类中包含公共行为的因素;但仍然存在一种隐式的公共性,即应用程序的不同“形状(即类型)”都必须支持某些使用公共语法的操作(也就是说,相关的函数必须具有相同的名称)。另外,具体类之间的定义是独立的(见下图)。于是,当使用具体类对模板实例化时,就实现了多态
在这里插入图片描述
现在我们改写上面的例子。

//  poly/coord.hpp
#include <cstdlib>

class Coord {
  private:
    int x, y;
  public:
    Coord (int i1, int i2) : x(i1), y(i2) {
    }
    friend Coord operator- (Coord const& c1, Coord const& c2) {
        return Coord(c1.x-c2.x, c1.y-c2.y);
    }
    Coord abs() {
        return Coord(std::abs(x),std::abs(y));
    }
};
 // poly/statichier.hpp
 
 //具体的集合对象类 Circle
// - 没有派生自任何其他的class
class Circle {
  public:
    void draw() const;
    Coord center_of_gravity() const;
    //...
};

// 具体的集合对象类 Circle
// - 没有派生自任何其他的class
class Line {
  public:
    void draw() const;
    Coord center_of_gravity() const;
    //...
};
//...
// poly/staticpoly.cpp

#include "statichier.hpp"
#include <vector>

// 画出任意 GeoObj
template <typename GeoObj>
void myDraw (GeoObj const& obj)
{
    obj.draw();      // 根据对象的类型调用相应的draw()
}

//计算两个GeoObjs对象之间中心的距离
template <typename GeoObj1, typename GeoObj2>
Coord distance (GeoObj1 const& x1, GeoObj2 const& x2)
{
    Coord c = x1.center_of_gravity() - x2.center_of_gravity();
    return c.abs();    // 返回坐标的绝对值
}

// draw homogeneous collection of GeoObjs
template <typename GeoObj>
void drawElems (std::vector<GeoObj> const& elems)
{
    for (unsigned i=0; i<elems.size(); ++i) {
        elems[i].draw();    // call draw() according to type of element
    }
}

int main()
{
    Line l;
    Circle c, c1, c2;

    myDraw(l);        // myDraw<Line>(GeoObj&) => Line::draw()
    myDraw(c);        // myDraw<Circle>(GeoObj&) => Circle::draw()

    distance(c1,c2);  // distance<Circle,Circle>(GeoObj1&,GeoObj2&)
    distance(l,c);    // distance<Line,Circle>(GeoObj1&,GeoObj2&)

    // std::vector<GeoObj*> coll;    // ERROR: no heterogeneous
                                   //      collection possible
    std::vector<Line> coll;   // OK: homogeneous collection possible
    coll.push_back(l);        // insert line
    drawElems(coll);          // draw all lines
}

静多态没有处理异类容器的能力,这是静多态的静态特性决定的:所有的类型都必须能够在编译器确定。但我们可以为不同的几何对象类型引入不同的集合

比较

严格的说,在C++中,动动态是绑定并且动态的多态的简称,静多态是非绑定的静态的多态的简称

  • 通过继承实现的多态是绑定的和动态的
    • 绑定的含义:对于参与多态行为的类型,它们(具有多态行为)的接口是在公共基类的设计中就预先确定的(绑定也叫做入侵或者插入的)
    • 动态的含义:接口的绑定是在运行期(动态)完成的
  • 通过模板实现的多态是非绑定的和静态的
    • 非绑定的含义:对于参与多态行为的类型,它们(具有多态行为)的接口是没有预先定义的(非绑定也叫做非入侵或者非插入的)
    • 静态的含义:接口的绑定是在编译期(静态)完成的

优缺点:

  • 动多态优点:

    • 能够优雅的处理异类集合
    • 可执行代码的大小通过比较小(因为只需要一个多态函数,但对于静多态而言,为了处理不同的代码,必须生成多个不同的实例)
    • 可以对代码进行完全编译,因此并不需要发布实现源码(但是,分发模板库通常都需要同时分发模板实现的源代码)
  • 静多态优点:

    • 可以很容易的实现内建类型的集合。更广义的说,并不需要通过公共基类来表达接口的共同性
    • 所生成的代码效率通常比较高(因为并不存在通过指针的简介调用,而且可以进行演绎的非虚拟函数具有更多的内联机会)
    • 对于只提供部分接口的具体类型,如果在应用程序中只使用这一部分接口,那么也可以使用该具体类型,而不必在乎该类型是否提供其他部分的接口

通常而言,静多态具有更好的类型安全性:因为静多态在编译期会对所有的绑定操作进行检查

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++是在C语言的基础上发展而来的一种编程语言,它在语法和特性上相对于C语言有一些重要的别。下面是些例子来说明C++编程与C语言之间的区别: 1. 面向对象编程(Object-Oriented Programming,OOP):C++是一种支持面向对象编程的语言,而C语言不直接支持。在C++中,可以使用类、对象、继承、多态等OOP的概念和特性来组织和设计程序,以提高代码的可重用性和可维护性。 2. 标准库(Standard Library):C++提供了一个丰富的标准库,包括容器(如vector、list)、算法(如排序、查找)、字符串处理、输入输出等。这些库提供了许多高级功能和数据结构,可以方便地完成各种任务,而C语言相对较少提供这样的标准库。 3. 异常处理(Exception Handling):C++引入了异常处理机制,可以通过抛出和捕获异常来处理程序中的错误。这使得在遇到错误时程序可以优雅地处理异常情况,并提供了更好的错误处理和代码健壮性。 4. 模板(Templates):C++引入了模板机制,允许编写泛型代码。模板可以实现通用的数据结构和算法,可以根据不同类型的数据进行参数化,从而提高代码的灵活性和可重用性。C语言没有这样的模板机制。 5. 命名空间(Namespace):C++引入了命名空间的概念,可以将代码分组到不同的命名空间中,避免命名冲突并提高代码的可读性和可维护性。C语言没有这样的命名空间机制。 6. 函数重载(Function Overloading):C++允许在同一个作用域内定义多个同名函数,但它们的参数列表不同。这被称为函数重载,它可以根据不同的参数类型和个数来自动选择调用哪个函数。而在C语言中,函数重载是不允许的。 上述例子只是一些常见的区别,C++还有很多其他特性,如引用、运算符重载、虚函数等,这些特性使得C++更加强大和灵活。但同时也需要注意,C++仍然保留了与C语言兼容的部分,所以在使用C++编程时可以兼顾使用C语言的部分特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值