zoukankan      html  css  js  c++  java
  • C++--第21课

    第21课 - 类模板 - 上

    思考:类是C++的核心,那是否能够将模板的思想应用于类呢?

    1. 类模板

    一些类主要用于存储和组织数据元素。如:数组类,链表类,Stack类,Queue类等等。

    C++中可以将模板的思想应用于类,使得类可以不关注具体所操作的数据类型,而是只关注所需要实现的功能。

    C++中的类模板,提供一种特殊的类似相同的行为处理不同的类型,在声明前使用template进行标识。

    <typename T>用于说明类中使用的泛指类型 T

    template<typename T>

    class Operator

    {

    public:

    T add(T a, T b)

    {

    return a + b;

    }

    T minus(T a, T b)

    {

    return a - b;

    }

    }

    声明的泛指类型T可用于声明成员变量和成员函数。

    编译器对类模板的处理方式和函数模板相同:编译器从类模板通过具体类型产生不同的类;编译器在声明的地方对类模板代码本身进行编译;编译器在使用的地方对参数替换后的代码进行编译。

    类模板的应用--使用具体类型定义对象

    Operator<int> op1; //对象op1用于处理int类型的加减法

    Operator<double> op2; //对象op2用于处理double类型的加减法

    cout<<op1.add(5, 4)<<endl;  //返回值也是int

    cout<<op2.minus(1.5, 0.01)<<endl;  //返回值也是double

    如果不看头两行代码,只看后面两行代码,我们无法知道,op1和op2究竟是处理什么的代码,会出现二义性,所以前两行的声明时必须的。

    类模板的工程应用

    由于类模板的编译机制不同,所以不能像普通类一样分开实现后再使用时包含头文件。在工程实践上,一般会把类模板的定义直接放到头文件中。只有被调用的类模板成员函数才会被编译器生成可执行代码。

    在模板类外部定义成员函数的实现上,需要加上template<typename T>的声明。

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename T>

    class Operator

    {

    public:

        T add(T a, T b);

        T minus(T a, T b);

    };

    template<typename T>

    T Operator<T>::add(T a, T b)

    {

        return a + b;

    }

    template<typename T>

    T Operator<T>::minus(T a, T b)

    {

        return a - b;

    }

    int main(int argc, char *argv[])

    {

        Operator<int> op1;

        Operator<double> op2;

        cout<<op1.add(5, 4)<<endl;

        cout<<op1.minus(4, 5)<<endl;

        cout<<op2.add(1.3, 0.01)<<endl;

        cout<<op2.minus(0.01, 1.3)<<endl;

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    9

    -1

    1.31

    -1.29

    2. 真正的数组类

    Array.h    

    #ifndef _ARRAY_H_

    #define _ARRAY_H_

    template<typename T>

    class Array

    {

    private:

        int mLength;

        T* mSpace;  //int* mSpace

    public:

        Array(int length);

        Array(const Array& obj);

        int length();

        ~Array();

        T& operator[](int i); // int& operator[](int i);

        Array& operator= (const Array& obj);

        bool operator== (const Array& obj);

        bool operator!= (const Array& obj);

    };

    #endifArray.hpp

    #ifndef _ARRAY_DEF_H_

    #define _ARRAY_DEF_H_

    #include "Array.h"

    template<typename T> //必须有 ,每个函数开头都有 

    Array<T>::Array(int length)//每个开头都有 Array<T>

    {

        if( length < 0 )

        {

            length = 0;

        } 

        mLength = length;

        mSpace = new T[mLength];

    }

    template<typename T>

    Array<T>::Array(const Array& obj)

    {

        mLength = obj.mLength;  

        mSpace = new int[mLength]; 

        for(int i=0; i<mLength; i++)

        {

            mSpace[i] = obj.mSpace[i];

        }

    }

    template<typename T>

    int Array<T>::length()

    {

        return mLength;

    }

    template<typename T>

    Array<T>::~Array()

    {

        mLength = -1;

       

        delete[] mSpace;

    }

    template<typename T>

    T& Array<T>::operator[](int i)

    {

        return mSpace[i];

    }

    template<typename T>

    Array<T>& Array<T>::operator= (const Array<T>& obj)

    {

        delete[] mSpace; 

        mLength = obj.mLength;

        mSpace = new int[mLength];

        for(int i=0; i<mLength; i++)

        {

            mSpace[i] = obj.mSpace[i];

        }

        return *this;

    }

    template<typename T>

    bool Array<T>::operator== (const Array<T>& obj)

    {

        bool ret = true; 

        if( mLength == obj.mLength )

        {

            for(int i=0; i<mLength; i++)

            {

                if( mSpace[i] != obj.mSpace[i] )

                {

                    ret = false;

                    break;

                }

            }

        }

        else

        {

            ret = false;

        }

        return ret;

    }

    template<typename T>

    bool Array<T>::operator!= (const Array& obj)

    {

        return !(*this == obj);

    }

    #endif

    main.cpp

    #include <cstdlib>

    #include <iostream>

    #include "Array.hpp"

    using namespace std;

    int main(int argc, char *argv[])

    {

        Array<int> ai(5);

        for(int i=0; i<ai.length(); i++)

        {

            ai[i] = i + 1;

        }

        for(int i=0; i<ai.length(); i++)

        {

            cout<<ai[i]<<endl;

        }

        Array<double> ad(10);

        for(int i=0; i<ad.length(); i++)

        {

            ad[i] = (i + 1) / 100.0;

        }

        for(int i=0; i<ad.length(); i++)

        {

            cout<<ad[i]<<endl;

        }

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    1

    2

    3

    4

    5

    0.01

    0.02

    0.03

    0.04

    0.05

    0.06

    0.07

    0.08

    0.09

    0.1

    分析:

    我们要是像以前一样包含的头文件是#include<Array.h>时。对于普通的类,编译函数的时候,会对main,.h,.cpp文件一起编译,并且生成代码。对于类模板,编译器遇到这三个文件的时候,发现是模板,就会去检查是否错误,而不会去生成代码,这里指的是Operator[]的代码。当编译到a[i] = i +1的时候,编译器就会想生成相应的操作符重载的代码,但是在main函数中,是没有这个函数的,所以此时语法会出错。所以我们采用的方法是加入头文件#include<Array.hpp>。我们这里为了防止重复包含,也是用了宏定义。#idndef #define #endif

    3. 类模板的特化

    类模板可以被特化,用template<>声明一个类时,表示这是一个特化类。

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename T>  //Test 类模板

    class Test

    {

    public:

        T test(T v)

        {

            cout<<"T test(T v)"<<endl;

            cout<<"sizeof(T) = "<<sizeof(T)<<endl;

            return v;

        }

    };

    template<>  //Test 类模板的 int化,也算是一种模板,只是只能是int

    class Test<int>

    {

    public:

        int test(int v)

        {

            cout<<"int test(int v)"<<endl;

            cout<<"sizeof(int) = "<<sizeof(int)<<endl;

           

            return v;

        }

    };

    class MyTest : public Test<int> //通过继承成较简单的特化类,也就是类模板特化的意义。

    {

    };

    int main(int argc, char *argv[])

    {

        Test<int> t1;

        Test<double> t2 ;

        cout<<t1.test(1)<<endl;

        cout<<t2.test(0.1)<<endl;

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    int test(int v)

    sizeof(int) = 4

    1

    T test(T v)

    sizeof(int) = 8

    0.1

    特化类模板的意义:

    当类模板在处理某种特定类型有缺陷时,可以通过类模板的特化来克服处理特定类型带来的不足。

    注意:编译器优先选择特化类生成对象。

  • 相关阅读:
    python机器学习-数据集划分
    python机器学习-数据集的使用
    char类型标识字段
    CharIndex的用法
    临时表和表变量性能差别
    建索引数据优化实例
    公用表达式的结果集不要子查询然后连接查询
    Oracle SQL in 超过1000 的解决方案
    Oracle 11g大数据量表快速增加列
    SQL Server表值函数
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336244.html
Copyright © 2011-2022 走看看