zoukankan      html  css  js  c++  java
  • 7、群体类和群体数据的组织-1.函数模板和类模板

    基本数据类型是c++编译系统预定义的,而自定义类型的数据是由多个基本类型或自定义类型的元素组成的,我们称之为群体数据

    对于群体数据,仅有系统预定义的操作是不够的,在很多情况下,还需要设计与某些具体问题相关的特殊操作,并按照面向对象的方法将数据与操作封装起来,这就是群体类

    群体可以分为两种:线性群体和非线性群体。线性群体中的元素按位置排列有序。非线性群体不用位置顺序来标识元素。

    关于群体数据的组织是属于数据结构的范畴,这里只介绍两类常用的算法:排序和查找方法。

    排序:又称为分类或整理,是将一个无序序列调整为有序的过程。在排序的过程中需要完成两种基本操作:一是比较两个数的大小,二是调整元素在序列中的位置。排序方法:直接插入排序、直接选择排序和起泡排序。

    查找:是在一个序列中按照某种方式找出需要的特定数据元素的过程。方法:顺序查找、折半查找。

    1、函数模板与类模板

    通用代码需要不受数据类型的影响并且可以自动适应数据类型的变化这种程序设计类型称为参数化程序设计

     模板是c++支持参数化程序设计的工具,通过它可以实现参数化多态性

    所谓参数化多态性就是将程序所处理的对象的类型参数化,使得一段程序可以用于处理多种不同类型的对象。

    1)函数模板

    程序员只需对函数模板编写一次,然后基于调用函数时提供的参数类型c++编译器将自动产生相应的函数来正确处理该类型的数据

    函数模板的定义形式是:

    template <class T> 或template <typename T>

    类型名 函数名(参数表)

    {函数体的定义}

    所有函数模板的定义都是用关键字template开始的,该关键字之后是使用尖括号<>括起来的类型参数表。每一个类型参数(例如上面语法形式的T)之前都有关键字class或关键字typename这些类型参数代表的是类型,可以是内部类型或自定义类型。这样类型参数可以用来指定函数模板本身的形参类型和返回值类型。以及声明函数中的局部变量。函数体的定义方式跟其他类似的。

    #include<iostream>

    using namespace std;

    template<typename T>

    T abs(T x)

    {

      return x<0?-x:x;

    }

    int main()

    {

      int n=-5;

      double d=-5.5;

      cout<<abs(n)<<endl;

      cout<<abs(d)<<endl;

    }

    在上述主函数中调用abs()时,编译器从实参的类型推导出函数模板的类型参数当类型参数的含义确定后,编译器将以函数模板为样板,生成一个对应实参类型的一个函数

    例子:

    #include<iosteam>

    using namespace std;

    template <class T>  //声明函数模板

    void outputArray(const T *P_array,const int count) //定义函数体

    {

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

      {

        cout<<P_array[i]<<"";

      }

      cout<<endl;

    }

    int main()

    {

      const int aCount=8,bCount=8,cCount=20;

      int aArray[aCount]={1,2,3,4,5,6,7,8};

      double bArray[bCount]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8};

      char cArray[cCount]="Welcome to see you!";

      cout<<"a Array contains:"<<endl;

      outputArray(aArray,aCount);//调用模板函数

      

      cout<<"b Array contains:"<<endl;

      outputArray(bArray,bCount);//调用模板函数

      cout<<"c Array contains:"<<endl;

      outputArray(cArray,cCount);//调用模板函数

    }

    由上面的实例可以看出,模板函数与重载是密切相关的,从函数模板产生的相关函数都是同名的,编译器用重载的解决方法调用相应的函数。另外函数模板本身也是可以用多种方式重载

    2)类模板

    使用类模板用户可以为类声明一种模式使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能取任意类型(包括系统预定义的和用户自定义的)。

    类模板则是对不同类的公共性质的抽象,因此类模板是属于更高层次的抽象。由于类模板需要一种或多种类型参数,所以类模板也常常称为参数化类。

    语法形式:

    template <模板参数表>

    class 类名

    {类成员声明}

    其中类成员声明的方法与普通类的定义几乎相同,只是在它的各个成员中通常要用到模板的类型参数T。

    如果需要在类模板以外定义其成员函数,则要采用以下的形式:

    template <模板参数表>

    类型名 类名<T> ::函数名(参数表)

    “模板参数表”由用逗号分隔的若干类型标识符或常量表达式构成,其内容包括:

    a、class(或typename)标识符,指明可以接受一个类型参数

    b、类型说明符 标识符,指明可以接受一个由“类型说明符”所规定的常量作为参数。

    当“模板参数表”同时包含上述多项内容时,各项内容以逗号分隔。应该注意的是,模板类的成员函数必须是函数模板

    一个类模板声明自身不产生代码,它说明了类的一个家族。只有当被其他代码引用时,模板才根据引用的需要产生代码。

    使用一个模板类来建立对象时,应按如下形式声明:

    模板<模板参数表> 对象名1,...,对象名n;

    通过把参数绑定到形式参数可以创建具体的类,这称为模板的实例化-生成具体的类。

    系统会根据指定的参数类型和常量值生成一个类,然后建立该类的对象。也就是说,对模板进行实例化生成类,再对类实例化便生成了对象。

    例子:类模板应用举例

    在本例中,声明一个实现任意类型数据存取的类模板Store,然后通过具体数据类型参数对模板进行实例化,生成类,然后再被实例化生成对象S1,S2,S3,D。不过类的实例化过程,在程序中是隐藏的。

    #include<iostream>

    #include<cstdlib>

    using namespace std;

    struct Student      //结构体

    Student {  

    int id;//学号

     float gpa;//平均分

    };

    template <class T>  //类模板:实现对任意类型数据进行存取

    class Store {

    private:  T item; //item用于存放任意类型的数据  

    int haveValue;//haveValue标记item是否已被存入内容

    public:  Store(void);//默认形式(无形参)的构造函数  

    T GetElem(void);//提取数据函数  

    void PutElem(T x);//存入数据函数

    };

    //以下实现各成员函数 //注意:模板类的成员函数,若在类外实现,则必须是模板函数

    template <class T>   //默认形式构造函数的实现

    Store<T>::Store(void) :haveValue(0) {}

    template <class T>  //提取数据函数的实现

    T Store<T>::GetElem(void)

    {  if (haveValue == 0)//如果试图提取为初始化的数据,则终止程序

     {  

     cout << "No item present!" << endl;

      exit(1);//使程序完全退出,返回到操作系统,参数可用来表示程序终止的原因,可以被操作系统接收

     }  return item;//返回item中存放的数据 }

    template <class T>  //存入数据函数的实现

    void Store<T>::PutElem(T x)

    {  haveValue++;//将haveValue置为TRUE,表示item中已存入数值

     item = x;//将x值存入item

    }

    int main()

    {  

    Student g = { 1000, 23 };//声明Student结构体变量的同时赋以初值  

    Store<int> S1,S2;//声明两个Store<int>类对象,其中数据成员item为int类型  

    Store<Student> S3;//声明Store<Student>类对象S3,其中数据成员item为Student类型  

    Store<double> D;//声明Store<double>类对象D,其中数据成员item为double类型

     S1.PutElem(3);//像对象S1中存入数据  

    S2.PutElem(-7);  

    cout << S1.GetElem() << " " << S2.GetElem() << endl;

     S3.PutElem(g);  

    cout << "The student is" << S3.GetElem().id << endl;

     cout << "Retrieving object D";  

    cout << D.GetElem() << endl;

     getchar();

     return 0; }

  • 相关阅读:
    Docker入门(windows版),利用Docker创建一个Hello World的web项目
    SpringBoot集成JWT实现token验证
    Jedis的基本操作
    Java动态代理详解
    SpringBoot利用自定义注解实现通用的JWT校验方案
    递归——汉诺塔问题(python实现)
    Datatable删除行的Delete和Remove方法的区别
    C# DEV使用心得
    总结
    安装插件时
  • 原文地址:https://www.cnblogs.com/gary-guo/p/6261470.html
Copyright © 2011-2022 走看看