zoukankan      html  css  js  c++  java
  • C++的优秀特性5:模版

    (转载请注明原创于潘多拉盒子)

      C++是强类型语言,而且恐怕是强类型语言里面类型最严格的。这意味着:1. C++变量的类型在定义时就确定了;2. 该类型在后续的生命期中不会改变。比如:

    int n = 0;
    n = 3.14159;    // n的类型不变,仍然为int型
    

    这样编译器产生的机器码是确定的,不需要运行时编译,比如像Python中的JIT(Just In Time)那样在代码执行过程中编译。

      但是,这给代码的可复用性带来了麻烦。比如现实中我们可能会定义一个二元关系"<",它表示“如果a < b,那么a在b前面”,或许你可以简单的理解为小于号,或者更广义的说,是a在b前面。那么你可能可以基于这个顺序的定义写一个排序函数。比如:

    void sort(int* array, int len)
    {
        // 某种排序实现,比如冒泡或者快速排序,就地对array中的元素进行排序
    }
    

    貌似就OK了!但仔细一看,不对!如果array是double型呢?幸好C++有重载(overload)机制,这事儿也不难:

    void sort(double* array, int len)
    {
        // 某种排序实现,比如冒泡或者快速排序,就地对array中的元素进行排序
    }

    由于是sort是完全基于 "<"运算符的,因此可以想想这两段实现代码看起来会非常像,出了中间变量的类型不同之外,其余都是相同的。甚至你可以直接拷贝粘贴,可以轻松实现float、long甚至是string的排序函数。

      不过,这很繁琐,不仅如此,还带来了维护的问题,如果代码需要改动呢?C++为解决这类问题,提供了模版机制,它允许程序员用"抽象类型"来暂时替代具体的类型,比如上述的例子可以写成:

    template <typename T>
    void sort(T* array, int len)
    {
        // 直接实现基于抽象类型T的排序函数,这里的类型T是可以在编译时确定的
    }
    

    注意,这段代码必须实现在头文件中,不可以实现在cpp中,除非该函数仅仅由该cpp调用。有了这样一个函数的定义,在客户代码中如何调用呢?该怎么调用就怎么调用,比如:

     std::string names[100];
    // load names ...
    sort(names, 100);    // 编译器在此时完成模版的实例化
    

      除了可以定义模版函数之外,还可以定义模版类,比如标准模版库(STL)就是基于模版机制实现的C++标准库。比如你可以定义一个类Any(boost库中有完整的实现boost::any),用于封装所有的类型。这个类可以定义成这样:

    class Any
    {
    public:
        Any() : _object(NULL), _type() {}
    
        Any(const Any& other) : _object(other._object), _type(other._type) {}
    
        Any& operator = (const Any& other)
        {
        _object = other._object;
        _type = other._type;
    return *this;
    } // 可以将任意类型T的对象存储在这个Any类型中   template <typename T>   Any& operator = (const T& object)   {     _holder = new T(object);     _type = typeid(T);
    return *this;   } // 定义了向已知类型T的转换操作   template <typename T>   T& cast()   {     if (typeid(T) != _type)     {       throw std::exception("bad type");     }     return *reinterpret_cast<T>(_object);   } private: void* _object; std::type_info _type; };

    这个类使用起来是这样的:

    std::string name = "ZHANG San";
    Any attribute = name;  // 这个any内部保存的类型被实例化为std::string
    std::string& anotherName = name.cast<std::string>();  // 由于没有参数列表,只能在模版实例化指示部分<std::string>定义实例化类型
    assert(name == anotherName);  // must be true
    

      或许,你需要定义一个容器类,像STL那样,保存某些元素:

    template <typename T>
    class Container
    {
    public:
        // 具体定义
    };
    
    // 客户代码
    Container<double> scores;
    

      

    C++的模版机制较复杂,实际使用中也会遇到不少问题,这里因为内容深度的限制,就不继续讨论了。

  • 相关阅读:
    【洛谷P3853】 [TJOI2007]路标设置
    【洛谷P1159】排行榜
    【洛谷P2921】[USACO08DEC]在农场万圣节
    【洛谷P1108】低价购买
    【洛谷P1363】幻象迷宫
    【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
    【数据结构】线段树的几种用法
    【题解】洛谷P1283 平板涂色(搜索+暴力)
    【题解】洛谷P1074 [NOIP2009TG] 靶形数独(DFS+剪枝)
    【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)
  • 原文地址:https://www.cnblogs.com/bqzhao/p/3551144.html
Copyright © 2011-2022 走看看