精华内容
下载资源
问答
  • 模板实例做模板参数

    千次阅读 2011-12-07 14:35:55
    未专用化的类 模板 不能用作 模板 变量,该变量属于 模板 参数“_Ty”,应为 real 类型 今天一个程序,在编译的时候遇到如上所述的问题。 代码如下:   C++语言: Codee#15880 template...

    未专用化的类 模板 不能用作 模板 变量,该变量属于 模板 参数“_Ty”,应为 real 类型

    今天做一个程序,在编译的时候遇到如上所述的问题。

    代码如下:

     

    C++语言Codee#15880
    template < typename  TYPE >
    struct  Node
    {
         TYPE  info;
         TYPE  newValue;         //保存该节点节点新一轮的质心
         TYPE  oldValue;         //保存该节点上一轮的质心
    };

    bool  K_Average( vector < Node >  set)
    {
       return true;
    }

    问题出在了一下这行:
    bool K_Average(vector<Node> set)

    错误提示:
     error C3203: “Node”: 未专用化的类 模板 不能用作 模板 变量,该变量属于 模板 参数“_Ty”,应为 real 类型
    这里Node本身是一个模板,在这里又作为另一个模板vector的模板变量,导致错误。

    先来看看MSDN 中是如何描述模板作为模板变量的:

    Template parameters can themselves be templates. This construct means that the argument must itself be a template, not a class constructed from template. In the following example, the name A of the template parameter for a template template parameter can be omitted, because there is no way that it can be used.

     

     

    C++语言Codee#15881
    // template_specifications3.cpp
    #include 

    template  < class  T >  struct  str1
    {
        T  t;
    };

    template  < template < class  A >  class  T >  struct  str2
    {
         T < int >  t;
    };

    int  main()
    {
         str2 < str1 >  mystr2;
         mystr2 . t . t  =  5;
         printf_s( "%d \n " ,  mystr2 . t . t);
    }
    也就是说将一个模板作为另一个模板的模板参数时候必须声明其是一个模板,而不能直接使用它作为一种新类型。

    修改后代码如下:
    C++语言Codee#15882
    template < typename  TYPE >
    struct  Node                //定义信息节点模板结构体
    {
         TYPE  info;
         TYPE  newValue;         //保存该节点节点新一轮的质心
         TYPE  oldValue;         //保存该节点上一轮的质心
    };

    template  < typename  TYPE >
    bool  K_Average( vector < Node < TYPE >  >  set)
    {
    return true;
    }
    展开全文
  • 说课ppt 非常漂亮 可以做模板

    热门讨论 2012-02-13 13:46:17
    非常漂亮的ppt 说课课件,有需要的可以下载!谢谢!
  • 在HTML中使用做模板

    千次阅读 2014-02-22 10:39:03
    有时我们会遇到在HTML中使用模板进行填充内容而又懒的使用文件操作(如XML)。 可以用本文中的方法: ... --------- ...然后在JS中先定义用于对带[]的内容替换的正则表达式var reg = new RegExp(
    有时我们会遇到在HTML中使用模板进行填充内容而又懒的使用文件操作(如XML)。
    
    可以用本文中的方法:

    html中加入标签,注意此时类型为text/html并在标签中加入任意HTML结构,需要动态定制的内容可用[]括起
    ---------
    <script type="text/html" id="item-template">
    <div>[Title]</div>
    <div>[Content]</div>
    </script>



    然后在JS中先定义用于对带[]的内容做替换的正则表达式
    var reg = new RegExp("\\[([^\\[\\]]*?)\\]", 'igm');//i gm是指分别用于指定区分大小写的匹配、全局匹配和多行匹配。
    var html =$('#item-template').html();//jquery获取id为item-template的element,取出里面的内容
    //再用如下方法进行内容替换,需区分大小写
    var source = html.replace(reg, function(node, key){
     
       return{'Title':'标题','Content':'往下翻'}[key];
    });
    alert(source);//<div>标题</div><div>内容</div>
    




    展开全文
  • 用Servlet+Hibernate写的小型权限管理系统,可实现对注册用户对系统的使用权限的控制 忘记告诉大家密码了:www.1166.tv 我的网站,希望大家也支持一下!
  • 易语言模板 易语言模易语言模板 易语言模板 易语言模板板 易语言模板易语言模板 易语言模板 易语言模板
  • latex中文ppt模板

    热门讨论 2013-07-24 08:44:39
    latex中文ppt模板,参加国际会议的人都可以用这个模板做自己想要的效果ppt,
  • C++函数模板模板函数)详解

    万次阅读 多人点赞 2019-07-04 16:03:01
    C++函数模板模板函数)详解定义用法:函数模板的原理延申用法2.1为什么需要类模板2.2单个类模板语法2.3继承中的类模板语法案例1:案例2:2.4类模板的基础语法2.5类模板语法知识体系梳理1.所有的类模板函数写在类的...

    定义

    函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。(好吧,咱也听不懂,直接上用法吧?)

    用法:

    面向对象的继承和多态机制有效提高了程序的可重用性和可扩充性。在程序的可重用性方面,程序员还希望得到更多支持。举一个最简单的例子,为了交换两个整型变量的值,需要写下面的 Swap 函数:

    void Swap(int & x, int & y)
    {
        int tmp = x;
        x = y;
        y = tmp;
    }
    

    为了交换两个 double 型变量的值,还需要编写下面的 Swap 函数:

    void Swap (double & xr double & y)
    {
        double tmp = x;
        x = y;
        y = tmp;
    }
    

    如果还要交换两个 char 型变量的值,交换两个 CStudent 类对象的值……都需要再编写 Swap 函数。而这些 Swap 函数除了处理的数据类型不同外,形式上都是一样的。能否只写一遍 Swap 函数,就能用来交换各种类型的变量的值呢?继承和多态显然无法解决这个问题。因此,“模板”的概念就应运而生了。

    众所周知,有了“模子”后,用“模子”来批量制造陶瓷、塑料、金属制品等就变得容易了。程序设计语言中的模板就是用来批量生成功能和形式都几乎相同的代码的。有了模板,编译器就能在需要的时候,根据模板自动生成程序的代码。从同一个模板自动生成的代码,形式几乎是一样的。

    函数模板的原理

    C++ 语言支持模板。有了模板,可以只写一个 Swap 模板,编译器会根据 Swap 模板自动生成多个 Sawp 函数,用以交换不同类型变量的值。

    在 C++ 中,模板分为函数模板和类模板两种。

    • 函数模板是用于生成函数;
    • 类模板则是用于生成类的。

    函数模板的写法如下:

    template <class 类型参数1, class类型参数2, ...>
    返回值类型  模板名(形参表)
    {
        函数体
    }
    

    其中的 class 关键字也可以用 typename 关键字替换,例如:

    template <typename 类型参数1, typename 类型参数2, ...>
    

    函数模板看上去就像一个函数。前面提到的 Swap 模板的写法如下:

    template <class T>
    void Swap(T & x, T & y)
    {
        T tmp = x;
        x = y;
        y = tmp;
    }
    

    T 是类型参数,代表类型。编译器由模板自动生成函数时,会用具体的类型名对模板中所有的类型参数进行替换,其他部分则原封不动地保留。同一个类型参数只能替换为同一种类型。编译器在编译到调用函数模板的语句时,会根据实参的类型判断该如何替换模板中的类型参数。

    例如下面的程序:

    #include <iostream>
    using namespace std;
    template<class T>
    void Swap(T & x, T & y)
    {
        T tmp = x;
        x = y;
        y = tmp;
    }
    int main()
    {
        int n = 1, m = 2;
        Swap(n, m);  //编译器自动生成 void Swap (int &, int &)函数
        double f = 1.2, g = 2.3;
        Swap(f, g);  //编译器自动生成 void Swap (double &, double &)函数
        return 0;
    }
    

    编译器在编译到Swap(n, m);时找不到函数 Swap 的定义,但是发现实参 n、m 都是 int 类型的,用 int 类型替换 Swap 模板中的 T 能得到下面的函数:

    void Swap (int & x, int & y)
    {
        int tmp = x;
        x = y;
        y = tmp;
    }
    

    该函数可以匹配Swap(n, m);这条语句。于是编译器就自动用 int 替换 Swap 模板中的 T,生成上面的 Swap 函数,将该 Swap 函数的源代码加入程序中一起编译,并且将Swap(n, m);编译成对自动生成的 Swap 函数的调用。

    同理,编译器在编译到Swap(f, g);时会用 double 替换 Swap 模板中的 T,自动生成以下 Swap 函数:

    void Swap(double & x, double & y)
    {
        double tmp = x;
        x = y;
        y = tmp;
    }
    

    然后再将Swap(f, g);编译成对该 Swap 函数的调用。

    编译器由模板自动生成函数的过程叫模板的实例化。由模板实例化而得到的函数称为模板函数。在某些编译器中,模板只有在被实例化时,编译器才会检查其语法正确性。如果程序中写了一个模板却没有用到,那么编译器不会报告这个模板中的语法错误。

    编译器对模板进行实例化时,并非只能通过模板调用语句的实参来实例化模板中的类型参数,模板调用语句可以明确指明要把类型参数实例化为哪种类型。可以用:

    模板名<实际类型参数1, 实际类型参数2, ...>
    

    的方式告诉编译器应该如何实例化模板函数。例如下面的程序:

    #include <iostream>
    using namespace std;
    template <class T>
    T Inc(int n)
    {
        return 1 + n;
    }
    int main()
    {
        cout << Inc<double>(4) / 2;
        return 0;
    }
    

    Inc(4)指明了此处实例化的模板函数原型应为:

    double Inc(double);
    

    编译器不会因为实参 4 是 int 类型,就生成原型为 int Inc(int) 的函数。因此,上面程序输出的结果是 2.5 而非 2。

    函数模板中可以有不止一个类型参数。例如,下面这个函数模板的写法是合法的:

    template <class Tl, class T2>
    T2 print(T1 argl, T2 arg2)
    {
        cout << arg1 << " " << arg2 << endl;
        return arg2;
    }
    

    【实例】一个求数组中最大元素的函数模板
    例题:设计一个分数类 CFraction,再设计一个名为 MaxElement 的函数模板,能够求数组中最大的元素,并用该模板求一个 CFmction 数组中的最大元素。

    示例程序如下:

    #include <iostream>
    using namespace std;
    template <class T>
    T MaxElement(T a[], int size) //size是数组元素个数
    {
        T tmpMax = a[0];
        for (int i = 1; i < size; ++i)
            if (tmpMax < a[i])
                tmpMax = a[i];
        return tmpMax;
    }
    class CFraction //分数类
    {
        int numerator;   //分子
        int denominator; //分母
    public:
        CFraction(int n, int d) :numerator(n), denominator(d) { };
        bool operator <(const CFraction & f) const
        {//为避免除法产生的浮点误差,用乘法判断两个分数的大小关系
            if (denominator * f.denominator > 0)
                return numerator * f.denominator < denominator * f.numerator;
            else
                return numerator * f.denominator > denominator * f.numerator;
        }
        bool operator == (const CFraction & f) const
        {//为避免除法产生的浮点误差,用乘法判断两个分数是否相等
            return numerator * f.denominator == denominator * f.numerator;
        }
        friend ostream & operator <<(ostream & o, const CFraction & f);
    };
    ostream & operator <<(ostream & o, const CFraction & f)
    {//重载 << 使得分数对象可以通过cout输出
        o << f.numerator << "/" << f.denominator; //输出"分子/分母" 形式
        return o;
    }
    int main()
    {
        int a[5] = { 1,5,2,3,4 };
        CFraction f[4] = { CFraction(8,6),CFraction(-8,4),
            CFraction(3,2), CFraction(5,6) };
        cout << MaxElement(a, 5) << endl;
        cout << MaxElement(f, 4) << endl;
        return 0;
    }
    

    编译到第 41 行时,根据实参 a 的类型,编译器通过 MaxElement 模板自动生成了一个 MaxElement 函数,原型为:

    int MaxElement(int a[], int size);
    

    编译到第 42 行时,根据 f 的类型,编译器又生成一个 MaxElement 函数,原型为:

    CFraction MaxElement(CFraction a[], int size);
    

    在该函数中,用到了<比较两个 CFraction 对象的大小。如果没有对<进行适当的重载,编译时就会出错。

    从 MaxElement 模板的写法可以看出,在函数模板中,类型参数不但可以用来定义参数的类型,还能用于定义局部变量和函数模板的返回值。

    延申用法

    2.1为什么需要类模板

    • 类模板与函数模板的定义和使用类似,我们已经进行了介绍。 有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类:

      在这里插入图片描述

    • 类模板用于实现类所需数据的类型参数化

    • 类模板在表示如数组、表、图等数据结构显得特别重要,

    • 这些数据结构的表示和算法不受所包含的元素类型的影响

    2.2单个类模板语法

     1 //类的类型参数化 抽象的类
     2 //单个类模板
     3 template<typename T>
     4 class A 
     5 {
     6 public:
     7     A(T t)
     8     {
     9         this->t = t;
    10     }
    11 
    12     T &getT()
    13     {
    14         return t;
    15     }
    16 protected:
    17 public:
    18     T t;
    19 };
    20 void main()
    21 {
    22    //模板了中如果使用了构造函数,则遵守以前的类的构造函数的调用规则
    23     A<int>  a(100); 
    24     a.getT();
    25     printAA(a);
    26     return ;
    27 }
    

    2.3继承中的类模板语法

    在这里插入图片描述

    案例1:

     1 //结论: 子类从模板类继承的时候,需要让编译器知道 父类的数据类型具体是什么(数据类型的本质:固定大小内存块的别名)A<int> 
     2 //
     3 class B : public A<int>
     4 {
     5 public:
     6     B(int i) : A<int>(i)
     7     {
     8 
     9     }
    10     void printB()
    11     {
    12         cout<<"A:"<<t<<endl;
    13     }
    14 protected:
    15 private:
    16 };
    17 
    18 //模板与上继承
    19 //怎么样从基类继承  
    20 //若基类只有一个带参数的构造函数,子类是如何启动父类的构造函数
    21 void pintBB(B &b)
    22 {
    23     b.printB();
    24 }
    25 void printAA(A<int> &a)  //类模板做函数参数 
    26 {
    27      //
    28     a.getT();
    29 }
    30 
    31 void main()
    32 {
    33     A<int>  a(100); //模板了中如果使用了构造函数,则遵守以前的类的构造函数的调用规则 
    34     a.getT();
    35     printAA(a);
    36 
    37     B b(10);
    38     b.printB();
    39 
    40 
    41     cout<<"hello..."<<endl;
    42     system("pause");
    43     return ;
    44 }
    

    案例2:

     1 #include<iostream>
     2 using namespace std;
     3 //A编程模板类--类型参数化
     4 /*
     5 类模板的定义 类模板的使用 类模板做函数参数
     6 */
     7 template <typename T>
     8 class A
     9 {
    10 public:
    11     A(T a = 0)
    12     {
    13         this->a = a;
    14     }
    15 public:
    16     void printA()
    17     {
    18         cout << "a:" << a << endl;
    19     }
    20 protected:
    21     T a;
    22 private:
    23     
    24 };
    25 //从模板类派生时,需要具体化模板类,C++编译器需要知道父类的数据类型是什么样子的
    26 //要知道父类所占的内存多少
    27 class B :public A<int>
    28 {
    29 public:
    30     B(int a =10, int b =20):A<int>(a)
    31     {
    32         this->b = b;
    33     }
    34     void printB()
    35     {
    36         cout << "a:" << a << "b:" << b << endl;
    37     }
    38 protected:
    39 private:
    40     int b;
    41     
    42 };
    43 //从模板类派生模板类
    44 template <typename T>
    45 class C :public A<T>
    46 {
    47 
    48 public:
    49     C(T c,T a) : A<T>(a)
    50     {
    51         this->c = c;
    52     }
    53     void printC()
    54     {
    55         cout << "c:" << c << endl;
    56     }
    57 protected:
    58     T c;
    59 private:
    60     
    61 };
    62 
    63 void main()
    64 {
    65     //B b1(1, 2);
    66     //b1.printB();
    67     C<int> c1(1,2);
    68     c1.printC();
    69 }
    

    2.4类模板的基础语法

     1 #include<iostream>
     2 using namespace std;
     3 //A编程模板类--类型参数化
     4 /*
     5     类模板的定义 类模板的使用 类模板做函数参数
     6 */
     7 template <typename T>
     8 class A
     9 {
    10 public:
    11     A(T a = 0)
    12     {
    13         this->a = a;
    14     }
    15 public:
    16     void printA()
    17     {
    18         cout << "a:" << a << endl;
    19     }
    20 protected:
    21 private:
    22     T a;
    23 };
    24 //参数 C++编译器具体的类
    25 void UseA(A<int> &a)
    26 {
    27     a.printA();
    28 }
    29 void main()
    30 {
    31     //模板类本身就是抽象的,具体的类,具体的变量
    32     A<int> a1(11),a2(22),a3(33);//模板类是抽象的, 需要类型具体化
    33     //a1.printA();
    34 
    35     UseA(a1);
    36     UseA(a2);
    37     UseA(a3);
    38 }
    

    2.5类模板语法知识体系梳理

    1.所有的类模板函数写在类的内部

    代码:

    复数类:

     1 #include<iostream>
     2 using namespace std;
     3 template <typename T>
     4 class Complex
     5 {
     6 public:
     7     friend Complex MySub(Complex &c1, Complex &c2)
     8     {
     9         Complex tmp(c1.a-c2.a, c1.b-c2.b);
    10         return tmp;
    11     }
    12 
    13     friend ostream & operator<< (ostream &out, Complex &c3)
    14     {
    15         out << c3.a << "+" << c3.b <<"i"<< endl;
    16         return out;
    17     }
    18     Complex(T a, T b)
    19     {
    20         this->a = a;
    21         this->b = b;
    22     }
    23     Complex operator+(Complex &c2)
    24     {
    25         Complex tmp(a + c2.a, b + c2.b);
    26         return tmp;
    27     }
    28     void printCom()
    29     {
    30         cout << "a:" << a << " b:" << b << endl;
    31     }
    32 protected:
    33 private:
    34     T a;
    35     T b;
    36 };
    37 
    38 /*
    39     重载运算符的正规写法:
    40     重载左移<<  右移>> 只能用友元函数,其他的运算符重载都要用成员函数,不要滥用友元函数
    41 */
    42 //ostream & operator<< (ostream &out, Complex &c3)
    43 //{
    44 //    out<< "a:" << c3.a << " b:" << c3.b << endl;
    45 //    return out;
    46 //}
    47 void main()
    48 {
    49     Complex<int>     c1(1,2);
    50     Complex<int>     c2(3, 4);
    51 
    52     Complex<int> c3 = c1 + c2;//重载加号运算符
    53     
    54     c3.printCom();
    55 
    56     //重载左移运算符
    57     cout << c3 << endl;
    58     
    59     {
    60         Complex<int> c4 = MySub(c1 , c2);
    61         
    62         cout << c4 << endl;
    63     }
    64     system("pause");
    65 }
    

    2.所有的类模板函数写在类的外部,在一个cpp中

    注意:

    复制代码
    //构造函数 没有问题

    • 普通函数 没有问题

    • 友元函数:用友元函数重载 << >>

      friend ostream& operator<< (ostream &out, Complex &c3) ;

    • 友元函数:友元函数不是实现函数重载(非 << >>)

    1 需要在类前增加 类的前置声明 函数的前置声明

    template<typename T>
    
    class Complex;  
    
    template<typename T>
    
    Complex<T> mySub(Complex<T> &c1, Complex<T> &c2);
    

    2 类的内部声明 必须写成:

    friend Complex<T> mySub <T> (Complex<T> &c1, Complex<T> &c2);
    

    3 友元函数实现 必须写成:

    template<typename T>
    
      Complex<T> mySub(Complex<T> &c1, Complex<T> &c2)
    
    {
    
    Complex<T> tmp(c1.a - c2.a, c1.b-c2.b);
    
    return tmp;
    
    }
    

    4 友元函数调用 必须写成

    Complex<int> c4 = mySub<int>(c1, c2);
    
    cout<<c4;
    

    结论:友元函数只用来进行 左移 友移操作符重载。

    复数类:

    代码:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 template<typename T>
     5 class Complex;
     6 template<typename T>
     7 Complex<T> mySub(Complex<T> &c1, Complex<T> &c2);
     8 
     9 template <typename T>
    10 class Complex
    11 {
    12 public:
    13     friend Complex<T> mySub <T>(Complex<T> &c1, Complex<T> &c2);
    14 
    15     friend ostream & operator<< <T>(ostream &out, Complex &c3);
    16     Complex(T a, T b);
    17     void printCom();
    18     Complex operator+(Complex &c2);
    19     Complex operator-(Complex &c2);
    20     
    21 protected:
    22 private:
    23     T a;
    24     T b;
    25 };
    26 
    27 //构造函数的实现,写在了外部
    28 template <typename T>
    29 Complex<T>::Complex(T a, T b)
    30 {
    31     this->a = a;
    32     this->b = b;
    33 }
    34 
    35 template <typename T>
    36 void Complex<T>::printCom()
    37 {
    38     cout << "a:" << a << " b:" << b << endl;
    39 }
    40 //成员函数实现加号运算符重载
    41 template <typename T>
    42 Complex<T> Complex<T>::operator+(Complex<T> &c2)
    43 {
    44     Complex tmp(a + c2.a, b + c2.b);
    45     return tmp;
    46 }
    47 template <typename T>
    48 Complex<T> Complex<T>::operator-(Complex<T> &c2)
    49 {
    50     Complex(a-c2.a,a-c2.b);
    51     return tmp;
    52 }
    53 //友元函数实现<<左移运算符重载
    54 
    55 /*
    56 严重性    代码    说明    项目    文件    行    禁止显示状态
    57 错误    C2768    “operator <<”: 非法使用显式模板参数    泛型编程课堂操练    
    58 
    59 错误的本质:两次编译的函数头,第一次编译的函数头,和第二次编译的函数有不一样
    60 */
    61 template <typename T>
    62 ostream & operator<< (ostream &out, Complex<T> &c3)//不加T
    63 {
    64     out << c3.a << "+" << c3.b << "i" << endl;
    65     return out;
    66 }
    67 
    68 
    69 //
    70 template <typename T>
    71 Complex<T> mySub(Complex<T> &c1, Complex<T> &c2)
    72 {
    73     Complex<T> tmp(c1.a - c2.a, c1.b - c2.b);
    74     return tmp;
    75 }
    76 
    77 void main()
    78 {
    79     Complex<int>     c1(1, 2);
    80     Complex<int>     c2(3, 4);
    81 
    82     Complex<int> c3 = c1 + c2;//重载加号运算符
    83 
    84     c3.printCom();
    85 
    86     //重载左移运算符
    87     cout << c3 << endl;
    88 
    89     {
    90         Complex<int> c4 = mySub<int>(c1, c2);
    91 
    92         cout << c4 << endl;
    93     }
    94     system("pause");
    95 }
    

    所有的类模板函数写在类的外部,在不同的.h和.cpp中
    也就是类模板函数说明和类模板实现分开

    //类模板函数

    构造函数

    普通成员函数

    友元函数

    用友元函数重载<<>>;

    用友元函数重载非<< >>

    demo_complex.cpp

     1 #include"demo_09complex.h"
     2 #include<iostream>
     3 using namespace std;
     4 
     5 template <typename T>
     6 Complex<T>::Complex(T a, T b)
     7 {
     8     this->a = a;
     9     this->b = b;
    10 }
    11 
    12 template <typename T>
    13 void Complex<T>::printCom()
    14 {
    15     cout << "a:" << a << " b:" << b << endl;
    16 }
    17 //成员函数实现加号运算符重载
    18 template <typename T>
    19 Complex<T> Complex<T>::operator+(Complex<T> &c2)
    20 {
    21     Complex tmp(a + c2.a, b + c2.b);
    22     return tmp;
    23 }
    24 //template <typename T>
    25 //Complex<T> Complex<T>::operator-(Complex<T> &c2)
    26 //{
    27 //    Complex(a - c2.a, a - c2.b);
    28 //    return tmp;
    29 //}
    30 template <typename T>
    31 ostream & operator<< (ostream &out, Complex<T> &c3)//不加T
    32 {
    33     out << c3.a << "+" << c3.b << "i" << endl;
    34     return out;
    35 }
    36 
    37 
    38 //
    39 //template <typename T>
    40 //Complex<T> mySub(Complex<T> &c1, Complex<T> &c2)
    41 //{
    42 //    Complex<T> tmp(c1.a - c2.a, c1.b - c2.b);
    43 //    return tmp;
    44 //}
    

    demo_09complex.h

     1 #pragma once
     2 #include<iostream>
     3 using namespace std;
     4 template <typename T>
     5 class Complex
     6 {
     7 public:
     8     //friend Complex<T> mySub <T>(Complex<T> &c1, Complex<T> &c2);
     9 
    10     friend ostream & operator<< <T>(ostream &out, Complex &c3);
    11     Complex(T a, T b);
    12     void printCom();
    13     Complex operator+(Complex &c2);
    14     //Complex operator-(Complex &c2);
    15 
    16 protected:
    17 private:
    18     T a;
    19     T b;
    20 };
    

    demo_09complex_text.cpp

     1 #include"demo_09complex.h"
     2 #include"demo_09complex.cpp"
     3 
     4 #include<iostream>
     5 using namespace std;
     6 
     7 void main()
     8 {
     9     Complex<int>     c1(1, 2);
    10     Complex<int>     c2(3, 4);
    11 
    12     Complex<int> c3 = c1 + c2;//重载加号运算符
    13 
    14     c3.printCom();
    15 
    16     //重载左移运算符
    17     cout << c3 << endl;
    18 
    19     /*{
    20         Complex<int> c4 = mySub<int>(c1, c2);
    21 
    22         cout << c4 << endl;
    23     }*/
    24     system("pause");
    25 }
    

    2.5总结

    归纳以上的介绍,可以这样声明和使用类模板:

    1. 先写出一个实际的类。由于其语义明确,含义清楚,一般不会出错。
    2. 将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的numtype)。
    3. 在类声明前面加入一行,格式为:

      template <class 虚拟类型参数>
    
      如:
    
          template <class numtype> //注意本行末尾无分号
    
          class Compare
    
            {…}; //类体
    
    1. 用类模板定义对象时用以下形式:

     类模板名<实际类型名> 对象名;
    
          类模板名<实际类型名> 对象名(实参表列);
    
      如:
    
          Compare<int> cmp;
    
          Compare<int> cmp(3,7);
    
    1. 如果在类模板外定义成员函数,应写成类模板形式:

     template <class 虚拟类型参数>
    
         函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列) {…}
    

    关于类模板的几点说明:

    1. 类模板的类型参数可以有一个或多个,每个类型前面都必须加class,如:

      template <class T1,class T2>
      
       class someclass
      
       {…};
      

      在定义对象时分别代入实际的类型名,如:

      someclass<int,double> obj;

    2. 和使用类一样,使用类模板时要注意其作用域,只能在其有效作用域内用它定义对象。

    3. 模板可以有层次,一个类模板可以作为基类,派生出派生模板类。

    2.6类模板中的static关键字

    从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
    每个模板类有自己的类模板的static数据成员副本

     1 #include<iostream>
     2 using namespace std;
     3 template <typename T>
     4 class AA
     5 {
     6 public:
     7     static T m_a;
     8 protected:
     9 private:
    10 };
    11 template <typename T>
    12 T AA<T>::m_a =0;
    13 void main()
    14 {
    15     AA<int> a1, a2, a3;
    16     a1.m_a = 10;
    17     a2.m_a++;
    18     a3.m_a++;
    19     cout << AA<int>::m_a << endl;
    20 
    21     AA<char> b1, b2, b3;
    22     b1.m_a = 'a';
    23     b2.m_a++;
    24     b3.m_a++;
    25     cout << AA<char>::m_a << endl;
    26 
    27     //m_a是每个类型的类,去使用,手工写两个类 int  char
    28     system("pause");
    29 }
    

    案例2:以下来自:C++类模板遇上static关键字

     1 #include <iostream>
     2 using namespace std;
     3 
     4 template<typename T>
     5 class Obj{
     6 public:
     7     static T m_t;
     8 };
     9 
    10 template<typename T>
    11 T Obj<T>::m_t = 0;
    12 
    13 int main04(){
    14     Obj<int> i1,i2,i3;
    15     i1.m_t = 10;
    16     i2.m_t++;
    17     i3.m_t++;
    18     cout << Obj<int>::m_t<<endl;
    19 
    20     Obj<float> f1,f2,f3;
    21     f1.m_t = 10;
    22     f2.m_t++;
    23     f3.m_t++;
    24     cout << Obj<float>::m_t<<endl;
    25 
    26     Obj<char> c1,c2,c3;
    27     c1.m_t = 'a';
    28     c2.m_t++;
    29     c3.m_t++;
    30     cout << Obj<char>::m_t<<endl;
    31 }
    

    当类模板中出现static修饰的静态类成员的时候,我们只要按照正常理解就可以了。static的作用是将类的成员修饰成静态的,所谓的静态类成员就是指类的成员为类级别的,不需要实例化对象就可以使用,而且类的所有对象都共享同一个静态类成员,因为类静态成员是属于类而不是对象。那么,类模板的实现机制是通过二次编译原理实现的。c++编译器并不是在第一个编译类模板的时候就把所有可能出现的类型都分别编译出对应的类(太多组合了),而是在第一个编译的时候编译一部分,遇到泛型不会替换成具体的类型(这个时候编译器还不知道具体的类型),而是在第二次编译的时候再将泛型替换成具体的类型(这个时候编译器知道了具体的类型了)。由于类模板的二次编译原理再加上static关键字修饰的成员,当它们在一起的时候实际上一个类模板会被编译成多个具体类型的类,所以,不同类型的类模板对应的static成员也是不同的(不同的类),但相同类型的类模板的static成员是共享的(同一个类)。

    2.7类模板在项目开发中的应用

    小结

    • 模板是C++类型参数化的多态工具。C++提供函数模板和类模板。

    • 模板定义以模板说明开始。类属参数必须在模板定义中至少出现一次。

    • 同一个类属参数可以用于多个模板。

    • 类属参数可用于函数的参数类型、返回类型和声明函数中的变量。

    • 模板由编译器根据实际数据类型实例化,生成可执行代码。实例化的函数。

    • 模板称为模板函数;实例化的类模板称为模板类。

    • 函数模板可以用多种方式重载。

    • 类模板可以在类层次中使用 。

    训练题

    1) 请设计一个数组模板类( MyVector ),完成对int、char、Teacher类型元素的管理。

    设计:

    • 类模板 构造函数 拷贝构造函数 << [] 重载=操作符

    • a2=a1

    • 实现

    2) 请仔细思考:

    a) 如果数组模板类中的元素是Teacher元素时,需要Teacher类做什么工作

    b) 如果数组模板类中的元素是Teacher元素时,Teacher类含有指针属性哪?

     1 class Teacher
     2 {
     3     friend ostream & operator<<(ostream &out, const Teacher &obj);
     4 public:
     5     Teacher(char *name, int age)
     6     {
     7         this->age = age;
     8         strcpy(this->name, name);
     9     }
    10 
    11     Teacher()
    12     {
    13         this->age = 0;
    14         strcpy(this->name, "");
    15     }
    16     
    17 private:
    18     int age;
    19     char name[32];
    20 };
    21 
    22 
    23 class Teacher
    24 {
    25     friend ostream & operator<<(ostream &out, const Teacher &obj);
    26 public:
    27     Teacher(char *name, int age)
    28     {
    29         this->age = age;
    30         strcpy(this->name, name);
    31     }
    32 
    33     Teacher()
    34     {
    35         this->age = 0;
    36         strcpy(this->name, "");
    37     }
    38     
    39 private:
    40     int age;
    41     char *pname;
    42 };
    

    结论1: 如果把Teacher放入到MyVector数组中,并且Teacher类的属性含有指针,就是出现深拷贝和浅拷贝的问题。

    结论2:需要Teacher封装的函数有:

    1. 重写拷贝构造函数

    2. 重载等号操作符

    3. 重载左移操作符。

    理论提高:

    所有容器提供的都是值(value)语意,而非引用(reference)语意。容器执行插入元素的操作时,内部实施拷贝动作。所以STL容器内存储的元素必须能够被拷贝(必须提供拷贝构造函数)。

    3) 请从数组模板中进行派生

     1 //演示从模板类 派生 一般类
     2 #include "MyVector.cpp"
     3 
     4 class MyArray01 : public MyVector<double>
     5 {
     6 public:
     7     MyArray01(int len) : MyVector<double>(len)
     8     {
     9         ;
    10     }
    11 protected:
    12 private:
    13 };
    14 
    15 
    16 //演示从模板类 派生 模板类 //BoundArray 
    17 template <typename T>
    18 class MyArray02 : public MyVector<T>
    19 {
    20 public:
    21     MyArray02(int len) : MyVector<double>(len)
    22     {
    23         ;
    24     }
    25 protected:
    26 private:
    27 };
    28 测试案例:
    29 
    30 //演示 从模板类 继承 模板类
    31 void main()
    32 {
    33     MyArray02<double> dArray2(10);
    34     dArray2[1] = 3.15;
    35 
    36 }
    37 
    38 
    39 //演示 从模板类 继承 一般类
    40 void main11()
    41 {
    42     MyArray01 d_array(10);
    43 
    44     for (int i=0; i<d_array.getLen(); i++)
    45     {
    46         d_array[i] = 3.15;
    47     }
    48 
    49     for (int i=0; i<d_array.getLen(); i++)
    50     {
    51         cout << d_array[i] << " ";
    52     }
    53 
    54     cout<<"hello..."<<endl;
    55     system("pause");
    56     return ;
    57 }
    

    作业:

    封装你自己的数组类;设计被存储的元素为类对象;

    思考:类对象的类,应该实现的功能。

    1. 优化Teacher类, 属性变成 char *panme, 构造函数里面 分配内存

    2. 优化Teacher类,析构函数 释放panme指向的内存空间

    3. 优化Teacher类,避免浅拷贝 重载= 重写拷贝构造函数

    4. 优化Teacher类,在Teacher增加 <<

    5. 在模板数组类中,存int char Teacher Teacher*(指针类型)

    zuoye.h

     1 #pragma once
     2 
     3 template <typename T>
     4 class MyVector
     5 {
     6 
     7     //friend ostream & operator<< <T>(ostream &out, const MyVector &obj);
     8 public:
     9     MyVector(int size = 0);//构造函数
    10     MyVector(const MyVector &obj);//copy构造函数
    11     ~MyVector();
    12 public:
    13     T& operator [](int index);
    14     MyVector &operator=(const MyVector &obj);
    15 
    16 
    17     int getLen()
    18     {
    19         return m_len;
    20     }
    21 protected:
    22 private:
    23     T *m_space;
    24     int m_len;
    25 
    26 };
    

    zuoye_test12.cpp

      1 #include"zuoye.h"
      2 #include"zuoye12.cpp"
      3 #include<iostream>
      4 using namespace std;
      5 class Teacher
      6 {
      7 public:
      8     Teacher()
      9     {
     10         age = 33;
     11         m_p = new char[1];
     12         strcpy(m_p, " ");
     13     }
     14 
     15     Teacher(char *name, int age)
     16     {
     17         this->age = age;
     18         m_p = new char[strlen(name)+1];
     19         strcpy(this->m_p, name);
     20 
     21     }
     22     Teacher(const Teacher &obj)
     23     {
     24         m_p = new char[strlen(obj.m_p) + 1];
     25         strcpy(this->m_p, obj.m_p);
     26         age = obj.age;
     27     }
     28     ~Teacher()
     29     {
     30         if (m_p!=NULL)
     31         {
     32             delete[] m_p;
     33             m_p = NULL;
     34         }
     35     }
     36     void printT()
     37     {
     38         cout << m_p << ", " << age;
     39     }
     40 public:
     41     //重载<< ==
     42     friend ostream & operator<<(ostream &out,Teacher &t);
     43     Teacher & operator=(const Teacher &obj) 
     44     {
     45         //1
     46         if (m_p!=NULL)
     47         {
     48             delete[] m_p;
     49             m_p = NULL;
     50             age = 33;
     51         }
     52         //2
     53         m_p = new char[strlen(obj.m_p) + 1];
     54         age = obj.age;
     55         //3
     56         strcpy(this->m_p, obj.m_p);
     57         return *this;
     58     }
     59 protected:
     60 private:
     61     int age;
     62     //char name[32];
     63     char *m_p;
     64 };
     65 ostream & operator<<(ostream &out, Teacher &t)
     66 {
     67     out << t.m_p << ", " << t.age << endl;
     68     return out;
     69 }
     70 
     71 void main()
     72 {
     73     Teacher t1("t1", 31), t2("t2", 32);
     74 
     75     MyVector<Teacher *> Tarray(2);
     76 
     77     Tarray[0] = &t1;
     78     Tarray[1] = &t2;
     79     for (int i = 0; i < 2; i++)
     80     {
     81         Teacher *tmp = Tarray[i];
     82         tmp->printT();
     83     }
     84     system("pause");
     85 }
     86 void main123()
     87 {
     88     Teacher t1("t1", 31), t2("t2", 32);
     89     MyVector<Teacher> Tarray(2);
     90     Tarray[0] = t1;
     91     Tarray[1] = t2;
     92     for (int i = 0; i < 2; i++)
     93     {
     94         Teacher tmp = Tarray[i];
     95         tmp.printT();
     96     }
     97     system("pause");
     98 }
     99 void main112()
    100 {
    101     MyVector<int>  myv1(10);
    102     myv1[0] = 'a';
    103     myv1[1] = 'b';
    104     myv1[2] = 'c';
    105     myv1[3] = 'd';
    106     myv1[4] = 'e';
    107     //cout << myv1;
    108     MyVector<int>  myv2 = myv1;
    109 }
    110 
    111 
    112 void main111()
    113 {
    114     MyVector<int>  myv1(10);
    115     for (int i = 0; i < myv1.getLen(); i++)
    116     {
    117         myv1[i] = i + 1;
    118         cout << myv1[i] << " ";
    119     }
    120 
    121     MyVector<int>  myv2 = myv1;
    122     for (int i = 0; i < myv2.getLen(); i++)
    123     {
    124         myv2[i] = i + 1;
    125         cout << myv2[i] << " ";
    126     }
    127 
    128     //cout << myv2 << endl;//重载左移运算符
    129 
    130     system("pause");
    131 }
    

    zuoye12.cpp

     1 #include"zuoye.h"
     2 #include<iostream>
     3 using namespace std;
     4 
     5 template <typename T>
     6 ostream & operator<<(ostream &out, const MyVector<T> &obj)
     7 {
     8     for (int i = 0; i<obj.m_len; i++)
     9     {
    10         out << obj.m_space[i] << " ";
    11     }
    12     out << endl;
    13     return out;
    14 }
    15 //构造函数
    16 template <typename T>
    17 MyVector<T>::MyVector(int size = 0)
    18 {
    19     m_space = new T[size];
    20     m_len = size;
    21 }
    22 //MyVector<int>  myv2 = myv1;
    23 template <typename T>
    24 MyVector<T>::MyVector(const MyVector &obj)
    25 {
    26     //根据大小分配内存
    27     m_len = obj.m_len;
    28     m_space = new T[m_len];
    29     //copy数据
    30     for (int i = 0; i<m_len; i++)
    31     {
    32         m_space[i] = obj.m_space[i];
    33     }
    34 }
    35 template <typename T>
    36 MyVector<T>::~MyVector()
    37 {
    38     if (m_space != NULL)
    39     {
    40         delete[] m_space;
    41         m_space = NULL;
    42         m_len = 0;
    43 
    44     }
    45 }
    46 template <typename T>
    47 T& MyVector<T>::operator [](int index)
    48 {
    49     return m_space[index];
    50 }
    51 template <typename T>
    52 MyVector<T> & MyVector<T>::operator=(const MyVector<T> &obj)
    53 {
    54     //先把a2的内存释放掉
    55     if (m_space != NULL)
    56     {
    57         delete[] m_space;
    58         m_space = NULL;
    59         m_len = 0;
    60 
    61     }
    62 
    63     //根据a1分配内存
    64     m_len = obj.m_len;
    65     m_space = new T[m_len];
    66 
    67     //copy数据
    68     for (i = 0; i<m_len; i += )
    69     {
    70         m_space[i] = obj.m_space[i];
    71     }
    72     return *this;//a2= a1 返回a2的自身
    73 }
    

    参考一些资料,加上一些见解,如果有雷同,纯属巧合。
    更多C++相关知识体系,请移步C++知识目录

    展开全文
  • c++函数模板做参数

    千次阅读 2016-12-04 16:14:20
    模板分为函数模板和类模板 今天我们来说说函数模板。 一:函数模版定义形式 template 类型形式参数表为: typename T1,typenameT2,......typenameTn 或者classT1,classT2,......classTn 函数模板声明形式 ...

    模板分为函数模板和类模板

    今天我们来说说函数模板。


    一:函数模版定义形式

    template <类型形式参数表>

    类型形式参数表为:

    typename T1,typenameT2,......typenameTn

    或者classT1,classT2,......classTn


    函数模板声明形式

    template <类型形式参数表>

    类型 函数名(形式参数表)

    {

    语句序列

    }


    函数模板的调用

    myswap<float>(a,b);//显示类型调用

    myswap(a,b);//自动数据类型推导


    二:函数模板做参数的实例

    代码如下

    #include <iostream>
    using namespace std;
    
    template <typename T, typename T1>
    int sort(T *array, T size)
    {
    	T1 i, j;
    	int temp = 0;
    	for (i = 0; i < size;i++)
    	{
    		for (j = i + 1; j < size;j++)
    		{
    			if (array[i] < array[j])
    			{
    				temp = array[i];
    				array[i] = array[j];
    				array[j] = temp;
    			}
    		}
    	}
    	return 0;
    }
    
    template <typename T, typename T1>
    int print(T *array,T1 size)
    {
    	T1 i;
    	for (i = 0; i < size;i++)
    	{
    		cout << array[i] << endl;
    	}
    	return 0;
    }
    
    int main()
    {
    	int array[] = { 11, 12, 32, 10, 222, 121 };
    	int size = sizeof(array) / sizeof(int);
    	sort<int,int>(array,size);
    	print<int, int>(array, size);
    
    	char array1[]="abcdfdgad";
    	int size1 = strlen(array1);
    	sort<char,int>(array1, size1);
    	print<char,int>(array1, size1);
    	return 0;
    }


    三:函数模板和普通函数的区别结论

    1, 函数模板不允许自动类型转化

    2.普通函数可以自动类型转化





    展开全文
  • C++模板、类模板、函数模板详解都在这里了

    万次阅读 多人点赞 2019-07-13 21:45:39
    C++模板、类模板、函数模板详解一、引言二、函数模板1、定义2、调用3、多个虚类型三、类模板1、定义2、调用四、类的函数模板五、类作为数据类型传入六、类模板与继承七、类模板与友元 一、引言 在写排序算法时,如果...
  • 内置175套flash企业网站模板,如果是个人想做个flash展示网站玩一下,完全没有问题,175套模板肯定够用,如果想要更多的模板,或者特别个性化的模板,那么本工具略显不够,您还是付费请官网帮你做模板,或者直接请建...
  • 什么是模板引擎:https://blog.csdn.net/weixin_43924228/article/details/86724134 ... 在前后端不分离的情况下,springboot推荐用html做页面,然后用thymeleaf做模板引擎,做数据渲染,但是这种方式...
  • 各种word宣传模板

    2010-07-02 16:08:17
    强大的word宣传模板,方便急需做模板的时候调用,简单而快捷,高效
  • 最近打算挑选几个STL容器个简单实现,发现里面牵涉到不少模板知识。这里算提前学习一下C++模板的相关知识吧。这次主要学习了什么是函数模板(这个最简单),类模板以及非类型模板参数。下面挨个举例说明。 文章...
  • Bootstrap程序员个人技术博客响应式模板基于Bootstrap3.3.5制作,界面简洁,自适应分辨率,兼容PC端和移动端,全套模板,包括首页、前端技术、后端程序、标签云、读者墙、友情链接、404错误页等网站模板页面。
  • JSP中使用JSP模板

    万次阅读 2017-05-13 20:25:24
    因为接触的少,我还是选择了使用JSP做模板引擎,然后就是如何引入了。 JSP的include分两种,静态inclued和动态include,二者区别在于静态include最后会编译成一个文件,所有的变量是共享的,而动态include是分开...
  • 函数模板( Function templates) 模板(Templates)使得我们可以生成通用的函数,这些函数能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载。这在一定程度上实现了宏...
  • flash 的选择题模板 开源

    热门讨论 2008-11-29 12:37:33
    flash 的选择题模板 用flash选择题是经常需要自己编辑和修改通用性很差。有了这个模板以后直接修改txt文件就能改选择题。通用性非常强。如果把它嵌入到你的文件中。或者增加一些判断特效,那么你就能作出维护...
  • ACM模板(满注释模板!)

    万次阅读 多人点赞 2020-04-13 22:00:52
    ACM模板,不同于其他大佬的是我这个模板是满注释的!哪怕是小白的你考场上都能快速上手算法,每一句都有注释帮你快速理解,方便对模板根据题意的修改
  • mui移动微商城模板h5模板 较完整的一套基于MUI框架的商城模板,分享出来大家学习借鉴
  • 模板匹配

    千次阅读 2019-03-07 21:50:39
    一. 模板匹配 模板匹配是数字图像处理的重要组成部分之一。...模板匹配就是在一幅大图像中搜寻目标,已知该图中有要找的目标,且该目标同模板有相同的尺寸、方向和图像,通过一定的算法可以在图中找到目标,确定...
  • 简历模板

    千次阅读 2018-05-26 23:31:39
    模板的使用 模板的介绍 模板1 模板2 模板3 模板4 模板5 模板6 模板7 模板8 模板9 模板10 模板11 模板12 模板13 模板14 模板15 准备 下载并安装LaTex 1.推荐下载网站: CTeX 2.9.2.164稳定版 2.安装:...
  • EXCEL的甘特图模板

    2018-08-21 11:17:09
    敏捷学习各种资料文档,自己个备份,也方便其他有需要的伙伴。
  • 用AxureWEB端的4个常见框架模板文件,另还有2个数据图表文件。WEB端设计的朋友,一定不要错过。
  • 模板三种类模板参数

    千次阅读 2018-04-22 10:40:47
    实际上有三种类型模板参数:类型模板参数、模板模板参数(以模板作为模板的参数)、无类型模板参数。 &nbsp; 1、类型模板参数 类型模板参数是我们使用模板的主要目的。我们可以定义多个类型模板参数: tem...
  • 模板当作一个类模板模板参数

    千次阅读 2018-03-24 09:25:08
    #include&...//类模板当作一个类的参数 //设计STL时候用到 //面试,类模板当作参数 class MyClass { public: private: }; template&lt;class T&gt; class MyClass2 { public: T...
  • 函数模板

    千次阅读 2016-06-09 17:32:11
    定义:什么是函数模板?一个可以应用于不同类型的对象的函数叫做函数模板。 函数模板可以让我们在不知道处理的数据是什么类型的情况下进行编程。起因:为什么C++中要增加模板?看下面三个函数:void swap(int& v1, ...
  • 搞一个进销存软件,要求入库单出库单的模板可以随时调整,并模板打印...暂时用EXCEL做模板,不过操作起来不是很舒服。有没有这样的控件啊~ 高手是不是都自定义这样的控件~~像用友 金蝶的进销存打印模板控件那样的~~~
  • 用asp动态网页模板 相当经典

    热门讨论 2009-10-19 18:34:17
    非常好的例子 值得下载。 用asp动态网页模板 相当经典
  • C++函数模板与类模板的区别

    万次阅读 多人点赞 2018-07-18 16:54:55
    模板: C++ 除了支持函数模板,还支持类模板(Class Template)。函数模板中定义的类型参数可以用在函数声明和函数定义中,类模板中定义的类型参数可以用在类声明和类实现中。类模板的目的同样是将数据的类型参数...
  • C++函数模板

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 694,686
精华内容 277,874
关键字:

如何做模板