• 7.1类模板


    类模板和虚函数,都是实现多态的重要方法。

    类模板,锁定算法、步骤,偏重类型相同。

    虚函数,偏重步骤不相同。

    9.3类模板

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

    类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响。

    类模板声明的一般方法如下:

    template<类模板参数>class 类名{//类体};

    用类模板定义对象的一般格式如下:

    类名<模板实例化参数类别>对象名(构造函数实参列表);

    //类模板实际上对于使用不同的数据类型,但是操作方法一样的类的一种抽象

    //类模板实现通用

     1 #include <iostream>
     2 
     3 //类模板实际上对于使用不同的数据类型,但是操作方法一样的类的一种抽象
     4 //类模板实现通用
     5 template <class T>
     6 class com
     7 {
     8 public:
     9     T a;
    10     T b;
    11     T add()
    12     {
    13         std::cout << typeid(T).name() << std::endl;
    14         return a + b;
    15     }
    16 };
    17 
    18 void main()
    19 {
    20     com<int>comx;
    21 
    22     comx.a = 19;
    23     comx.b = 29;
    24 
    25     std::cout << comx.add() << std::endl;
    26 
    27     system("pause");
    28 }

    //定义两种数据类型的类模板

    //STL数据结构,算法,适用任何类型

     1 #include <iostream>
     2 #include <string>
     3 
     4 //定义两种数据类型的类模板
     5 //STL数据结构,算法,适用任何类型
     6 template<class T1, class T2>
     7 class myclass
     8 {
     9 public:
    10     T1 t11;
    11     T2 t22;
    12     myclass(T1 t111, T2 t222) :t11(t111), t22(t222)
    13     {
    14 
    15     }
    16     void print()
    17     {
    18         std::cout << t11 << " " << t22 << std::endl;
    19     }
    20 };
    21 
    22 void main()
    23 {
    24     myclass<int, double>my1(10, 20.8);
    25     my1.print();
    26 
    27     myclass<double, std::string>my2(20.8, "123456abc");
    28     my2.print();
    29 
    30     system("pause");
    31 }

    //类模板可以有一个默认的值,C++11

     1 #include "myArray.h"
     2 
     3 template<class T = int>//类模板可以有一个默认的值,C++11
     4 myArray<T>::myArray()
     5 {
     6     std::cout << "构造" << typeid(T).name() << std::endl;
     7 }
     8 
     9 template<class T = int>//类模板可以有一个默认的值,C++11
    10 myArray<T>::~myArray()
    11 {
    12     std::cout << "销毁" << typeid(T).name() << std::endl;
    13 }

    9.3.2类模板作函数参数

    函数的形式参数类型可以是类模板或类模板的引用。对应的实际参数是该类模板实例化的模板类对象。

    当一个函数拥有类模板参数时,这个函数必定是函数模板。

    9.3.3在类层次中的类模板

    类模板派生普通类,在定义派生类时要对基类的抽象类参数实例化。

    从普通类派生模板类,意味着派生类添加了抽象类数据成员。

    一个类模板在类层次结构中既可以是基类也可以是派生类:

    1类模板可以从模板类派生。

    2类模板可以从非模板类派生。

    3模板类可以从类模板派生。

    4非模板类可以从类模板派生。

    //类模板可以直接继承类模板,但是类型必须传递

    //普通类继承类模板,需要明确类型实例化类模板

    //类模板继承普通类,常规操作方式

    //类模板当作普通类使用,需要模板参数实例化

    类模板->类模板

     1 #include <iostream>
     2 #include <string>
     3 
     4 //模板类的继承
     5 
     6 template <class T>
     7 class myclass//基类
     8 {
     9 public:
    10     T x;
    11     myclass(T t) :x(t)//构造函数
    12     {
    13 
    14     }
    15     void print()
    16     {
    17         std::cout << x << std::endl;
    18     }
    19 };
    20 
    21 template <class T>
    22 class newclass :public myclass<T>//派生类
    23 {
    24 public:
    25     T y;
    26     newclass(T t1, T t2) :myclass(t1), y(t2)//构造函数
    27     {
    28 
    29     }
    30     void print()
    31     {
    32         std::cout << x << " " << y << std::endl;
    33     }
    34 };
    35 
    36 void main()
    37 {
    38     newclass<double>my1(10.9, 2.3);
    39     my1.print();
    40 
    41     newclass<std::string>my2("abc", "xyz");
    42     my2.print();
    43     
    44     system("pause");
    45 }

    普通类->类模板

     1 #include <iostream>
     2 #include <string>
     3 
     4 class xyz//基类
     5 {
     6 public:
     7     int x;
     8     int y;
     9     int z;
    10     xyz(int a, int b, int c) :x(a), y(b), z(c)//构造函数
    11     {
    12 
    13     }
    14     void print()
    15     {
    16         std::cout << x << " " << y << " " << z << std::endl;
    17     }
    18 };
    19 
    20 template<class T>
    21 class newxyz :public xyz//派生类
    22 {
    23 public:
    24     T a;
    25     newxyz(T t1, int a1, int b1, int c1) :xyz(a1, b1, c1), a(t1)//构造函数
    26     {
    27 
    28     }
    29     void print()
    30     {
    31         std::cout << "Ta=" << a << std::endl;
    32         std::cout << x << " " << y << " " << z << std::endl;
    33     }
    34 };
    35 
    36 void main()
    37 {
    38     std::string str1 = "china";
    39     newxyz<std::string> new1(str1, 10, 90, 89);
    40     new1.print();
    41     
    42     system("pause");
    43 }

    普通类->类模板->普通类

     1 #include <iostream>
     2 #include <string>
     3 
     4 //类模板可以直接继承类模板,但是类型必须传递
     5 //普通类继承类模板,需要明确类型实例化类模板
     6 //类模板继承普通类,常规操作方式
     7 //类模板当作普通类使用,需要模板参数实例化
     8 
     9 class xyz//父类
    10 {
    11 public:
    12     int x;
    13     int y;
    14     int z;
    15     xyz(int a, int b, int c) :x(a), y(b), z(c)//构造函数
    16     {
    17 
    18     }
    19     void print()
    20     {
    21         std::cout << x << " " << y << " " << z << std::endl;
    22     }
    23 };
    24 
    25 template<class T>
    26 class newxyz :public xyz//子类
    27 {
    28 public:
    29     T a;
    30     newxyz(T t1, int a1, int b1, int c1) :xyz(a1, b1, c1), a(t1)//构造函数
    31     {
    32 
    33     }
    34     void print()
    35     {
    36         std::cout << "Ta=" << a << std::endl;
    37         std::cout << x << " " << y << " " << z << std::endl;
    38     }
    39 };
    40 
    41 class classrun :public newxyz<int>//孙类
    42 {
    43 public:
    44     int d = 1000;
    45     classrun(int a2, int b2, int c2, int d2) :newxyz<int>(a2, b2, c2, d2)//构造函数
    46     {
    47 
    48     }
    49     void print()
    50     {
    51         std::cout << d << " " << x << " " << y << " " << z << " " << a << std::endl;
    52     }
    53 };
    54 
    55 void main()
    56 {
    57     classrun run1(1, 2, 3, 4);
    58     run1.print();
    59 
    60     system("pause");
    61 }
    62 
    63 void main3()
    64 {
    65     std::string str1 = "china";
    66     newxyz<std::string> new1(str1, 10, 90, 89);
    67     new1.print();
    68     
    69     system("pause");
    70 }

    面试:什么是模板抽象类?

    模板抽象类,不能说明抽象类的对象,但可以说明指向抽象类对象的指针(或引用)

     1 #include <iostream>
     2 
     3 template <class T>//模板抽象类,不能说明抽象类的对象,但可以说明指向抽象类对象的指针(或引用)
     4 class myclass
     5 {
     6 public:
     7     T x;
     8     myclass(T t) :x(t)//构造函数
     9     {
    10 
    11     }
    12     virtual void print() = 0;//纯虚函数
    13 };
    14 
    15 template <class T>
    16 class newclass :public myclass<T>
    17 {
    18 public:
    19     T y;
    20     newclass(T t1, T t2) :myclass(t1), y(t2)//构造函数
    21     {
    22 
    23     }
    24     virtual void print()//虚函数
    25     {
    26         std::cout << x << " " << y << std::endl;
    27     }
    28 };
    29 
    30 void main()
    31 {
    32     myclass<int> *p = new newclass<int>(10, 9);//模板抽象类,不能说明抽象类的对象,但可以说明指向抽象类对象的指针(或引用)
    33     p->print();//10 9
    34     
    35     system("pause");
    36 }

    9.3.4类模板与友元

    在类模板中可以声明各种友元关系

    一个函数或函数模板可以是类或类模板的友元。

    一个类或类模板可以是类或类模板的友元类。

    声明这种模板之间的友元关系符号比较烦琐。

    1友元函数在类模板的内部定义

    2友元函数在类模板的外部定义

    1友元函数在类模板的内部定义

    operator友元运算符重载+,实现两个类的对象的x和y分别相加

     1 #include <iostream>
     2 
     3 template <class T>
     4 class myclass
     5 {
     6 private:
     7     T x;
     8     T y;
     9 public:
    10     myclass(T t1, T t2) :x(t1), y(t2)//构造函数
    11     {
    12 
    13     }
    14     friend void print(myclass<T> &my)//友元函数在类模板的内部定义
    15     {
    16         std::cout << my.x << " " << my.y << std::endl;
    17     }
    18     friend myclass * operator+(const myclass<T> &my1, const myclass<T> &my2)//重载+
    19     {
    20         myclass *p = new myclass(my1.x + my2.x, my1.y + my2.y);//创建在堆上,为了返回
    21         return p;        
    22     }
    23 };
    24 
    25 void main()
    26 {
    27     myclass<int>my1(19, 29);
    28     myclass<int>my2(11, 1);
    29 
    30     myclass<int> *pclass = my1 + my2;//重载+
    31 
    32     print(*pclass);//30 30
    33         
    34     system("pause");
    35 }

    2友元函数在类模板的外部定义

    //如果友元函数在类模板的外部定义,第1声明要加类型T,第2必须上方声明类和函数

     1 #include <iostream>
     2 template<class T> class myclass;//声明类
     3 template<class T> void print(myclass<T> & my);//声明函数
     4 
     5 //如果友元函数在类模板的外部定义,第1声明要加类型T,第2必须上方声明类和函数
     6 
     7 template<class T>
     8 class myclass
     9 {
    10 private:
    11     T x;
    12 public:
    13     myclass(T t) :x(t)
    14     {
    15 
    16     }
    17     friend void print<T>(myclass<T> & my);//声明友元函数
    18 };
    19 
    20 template<class T>
    21 void print(myclass<T> & my)//定义友元函数
    22 {
    23     std::cout << my.x << std::endl;
    24 }
    25 
    26 void main()
    27 {
    28     myclass<int>my1(10);
    29     myclass<double>my2(10.9);
    30 
    31     print(my1);//10
    32     print(my2);//10.9
    33 
    34     system("pause");
    35 }

    类模板和友元类

     1 #include <iostream>
     2 template<class T> class runclass;//声明友元类
     3 
     4 //友元类必须声明类的存在
     5 //需要声明友元类,必须要与类型相关
     6 
     7 template<class T>
     8 class myclass
     9 {
    10 private:
    11     T x;
    12 public:
    13     myclass(T t) :x(t)
    14     {
    15 
    16     }
    17     friend class runclass<T>;//声明友元类
    18 };
    19 
    20 template<class T>
    21 class runclass//定义友元类
    22 {
    23 public:
    24     void print(const myclass<T> & my)//打印不修改,const引用
    25     {
    26         std::cout << my.x << std::endl;
    27     }
    28 };
    29 
    30 void main()
    31 {
    32     myclass<double>my1(10.9);
    33     runclass<double>run1;
    34 
    35     run1.print(my1);
    36     
    37     system("pause");
    38 }

    面试,类模板当作类模板的参数

     1 #include <iostream>
     2 #include <string>
     3 
     4 //面试,类模板当作类模板的参数
     5 
     6 template<class T>
     7 class ren//一个通用类型的类模板
     8 {
     9 public:
    10     T name;
    11     ren(T t) :name(t)//构造函数
    12     {
    13 
    14     }
    15 };
    16 
    17 template<template<class T>class T1>
    18 class people//类模板当作类模板的参数
    19 {
    20 public:
    21     T1<std::string>t1x = "123";//T1必须实例化,必须结合
    22     T1<std::string>num = "ABC";//等价于ren类型
    23     people(T1<std::string>t1)//构造函数
    24     {
    25         std::cout << typeid(t1).name() << std::endl;//打印类型
    26         std::cout << typeid(T1).name() << std::endl;//打印类型
    27     }
    28 };
    29 
    30 void main()
    31 {
    32     ren<std::string>ren1("hello");//基本数据类型
    33     people<ren>people1(ren1);
    34 
    35     std::cout << people1.t1x.name << std::endl;
    36     std::cout << people1.num.name << std::endl;
    37     
    38     system("pause");
    39 }

    9.3.5类模板与static成员

    从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员。

    和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化。

    每个模板类有自己的类模板的static数据成员副本。

    //类模板的static静态数据成员,访问方式:1对象,2类名<数据类型>

    //不同数据类型的静态数据成员,地址不一样

    //相同数据类型的静态数据成员,地址一样

     1 #include <iostream>
     2 #include <string>
     3 
     4 //类模板的static静态数据成员,访问方式:1对象,2类名<数据类型>
     5 //不同数据类型的静态数据成员,地址不一样
     6 //相同数据类型的静态数据成员,地址一样
     7 
     8 template<class T>
     9 class myclass
    10 {
    11 public:
    12     static int num;//声明静态数据成员
    13     T a;
    14     myclass(T t) :a(t)//构造函数
    15     {
    16         num++;//计数器
    17     }
    18 };
    19 
    20 template<class T>
    21 int myclass<T>::num = 0;//初始化静态数据成员
    22 
    23 void main()
    24 {
    25     myclass<int>my1(10);
    26     myclass<double>my2(10.9);
    27     myclass<std::string>my3("1234");
    28     myclass<int>my4(10);
    29 
    30     //访问方式:1对象
    31     std::cout << my1.num << std::endl;//2
    32     std::cout << my2.num << std::endl;//1
    33     std::cout << my3.num << std::endl;//1
    34     std::cout << my4.num << std::endl;//2
    35 
    36     //发现<int>的地址一样
    37     std::cout << &my1.num << std::endl;//一样
    38     std::cout << &my2.num << std::endl;
    39     std::cout << &my3.num << std::endl;
    40     std::cout << &my4.num << std::endl;//一样
    41     
    42     //访问方式:2类名<数据类型>
    43     std::cout << myclass<int>::num << std::endl;
    44     
    45     system("pause");
    46 }

    类模板以及类模板嵌套

    一个普通类的对象作为一个类模板的成员,可以紧跟在类说明之后进行定义

    一个类模板的对象作为一个类模板的成员,不可以紧跟在类说明之后进行定义

     1 #include <iostream>
     2 
     3 template<class T>
     4 class myclass
     5 {
     6 public:
     7     class newclass
     8     {
     9     public:
    10         int num;
    11     }new1;//一个普通类的对象作为一个类模板的成员,可以紧跟在类说明之后进行定义
    12 
    13     template<class V>
    14     class runclass
    15     {
    16     public:
    17         V v1;
    18     };//一个类模板的对象作为一个类模板的成员,不可以紧跟在类说明之后进行定义
    19     runclass<T>t1;//先说明类,再单独进行变量定义
    20     runclass<double>t2;//先说明类,再单独进行变量定义
    21 };
    22 
    23 void main()
    24 {
    25     myclass<int> my1;
    26     my1.new1.num = 10;
    27 
    28     my1.t1.v1 = 12;
    29     my1.t2.v1 = 12.9;
    30 
    31     std::cout << my1.t1.v1 << std::endl;//12
    32     std::cout << my1.t2.v1 << std::endl;//12.9
    33 
    34     system("pause");
    35 }

    小结

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

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

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

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

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

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

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

  • 相关阅读:
    log4j2 工具类
    Intellij IDEA的快捷键
    Intellij IDEA设置忽略部分类编译错误
    idea 激活
    DataGrip使用入门
    IDEA Run/Debug Configurations 中点击“+”号没有tomcat server选项
    临时
    java异常类
    java匿名类
    java内部类
  • 原文地址:https://www.cnblogs.com/denggelin/p/5671693.html
Copyright © 2020-2023  润新知