zoukankan      html  css  js  c++  java
  • STL学习笔记(第二章 C++及其标准程序库简介)

    本章重点是介绍与C++标准程序库相关的几个最重要的语言新特性

    template(模板)

    程序库中几乎所有东西都被设计成template形式。所谓templates,是针对“一个或多个尚未明确的型别”所撰写的函数或类别。

    下面是一个典型例子

     template<class T>
     inline const T& max(const T& a,const T& b)
     {
          return a < b ? b : a;
     {

    template并非一次编译便产生出社和所有型别的代码,而是针对被使用的某个(或某组)型别进行编译。因此你必须先提供它的某个实作品才能调用。

    Nontype Templates参数(非型别模板参数)

    型别(type)可作为template参数,非型别(nontype)也可以作为template参数。例如可以把标准类别bitset<>的bits数量以template参数指定。下面定义两个由bits构成的容器,分别为32个bits空间和50个bits空间。

    bitset<32> flags32;
    bitset<50> flags50;

    Default Template Parameters(缺省模板参数)

    Template classes可以有缺省参数。例如以下声明,允许你使用一个或两个template参数来声明MyClass对象。

    template <class T,class container = vector<T> >
    class MyClass;

    关键字typename

    关键字typename被用来作为型别之前的标识符号。考虑下面例子:

    template <class T>
    class MyClass
    {
           typename T::SubType *ptr;
           ...
    };

    这里,typename指出SubType是class T中定义的一个型别,因此ptr是一个指向T::SubType型别的指针。

    如果没有关键字typename,SubType会被当成一个static成员,于是T::SubType *ptr会被解释为型别T内的数值SubType与ptr的乘积。

    typename还可以在template声明中用来替代关键字class:

    template <typename T>
    class MyClass;

    Member Template(成员模板)

    class member function可以是个template,但这样的member template既不能是virtual,也不能有缺省参数,例如:

    class MyClass
    {
          ...
          template <class T>
          void f(T);
    };

    这里的MyClass::f声明了一个成员函数集,使用任何型别参数。这个特性通常用来为template classes中的成员提供自动型别转换。

    如果使用类模板,其型别必须和调用端所提供的对象的型别完全吻合:

    template <class T>
    class MyClass
    {
        private:
            T value;
        public:
            void assign(const MyClass<T>& x) {value=x.value;}
        ...  
    };
    
    void f()
    {
         MyClass<double> d;
         MyClass<int> i;
         d.assign(d)            //OK
         d.assign(i)             //ERROR
    }
    View Code

    而member template function可以放宽“必须精确吻合”这条规则。只要型别可被赋值,就可以被当做其函数参数。

    template <class T>
    class MyClass{
         private:
             T value;
         public:
             template <class X>
             void assign(const MyClass<X>& x) {value=x.getValue();}
             T getValue () const {return value;}
    };
    
    void f()
    {
         MyClass<double> d;
         MyClass<int> i;
         d.assign(d);   //OK
         d.assign(i);    //OK
    }
    View Code

    因为assign()参数x和*this的型别并不相同,所以不能直接存取MyClass<>的private成员和protected成员,因此要提供类似getValue()之类的东西。

    template constructor是member template的一种特殊形式。template constructor并不遮蔽implicit copy constructor。如果型别完全吻合,implicit copy constructor就会被产生出来并被调用。

    template <class T>
    class MyClass{
       public:
           template <class U>
           MyClass(const MyClass<U>& x);
           ...
    };
    
    void f()
    { 
         MyClass<double> xd;
         MyClass<double> xd2(xd)  //calls built-in copy constructor
         MyClass<int> xi(xd)           //calls template constructor
    }
    View Code

    基本型别的显示初始化(Explicit Initialization)

    如果采用不含参数的、明确的constructor调用语法,基本型别会被初始化为零:

    int i1;            //undefined value
    int i2=int();   //initialized with zero

    这个特性可以确保我们在撰写template程序代码时,任何型别都有一个确切的初值:

    template <class T>
    void f()
    {
        T x=T();
        ...
    }

    关键字explicit

    通过关键字explicit的作用,我们可以禁止“单参数构造函数”被用于自动型别转换。

    class Stack{
        explicit Stack(int size);
        ...
    };

    如果没有explicit,这个构造函数有能力将一个int自动转换成Stack。在这种情况下,可以给Stack指派一个整数值而不会引起任何问题:

    Stack s;
    ...
    s=40  //create a new Stack for 40 elements and assigns it to s

    而使用了explicit的构造函数则会使上述赋值操作导致编译错误。

  • 相关阅读:
    LintCode "Maximum Gap"
    LintCode "Wood Cut"
    LintCode "Expression Evaluation"
    LintCode "Find Peak Element II"
    LintCode "Remove Node in Binary Search Tree"
    LintCode "Delete Digits"
    LintCode "Binary Representation"
    LeetCode "Game of Life"
    LintCode "Coins in a Line"
    LintCode "Word Break"
  • 原文地址:https://www.cnblogs.com/runnyu/p/4812476.html
Copyright © 2011-2022 走看看