模板简要介绍,C++读书笔记

2014年2月3日   内容整理自《程序设计教程:  用C++语言编程 第三版》 陈家骏  郑滔

---------------------------------------------------------------------------------------------------------------------------------

(一)函数模板

1)类属函数和类属类

  • 类属函数是指一个函数能够对不同类型的数据(参数)完成相同的操作。
  • 类属类是指一个类的成员类型可变,从而可以用它描述不同种类的对象。

C++是一个静态类型语言,它提供了多种实现类属函数的途径,其中包括:

  • 宏定义
  • 指针类型
  • 函数模板

其中宏定义虽然能实现类属函数的效果,但它毕竟不是函数,而只是在编译之前的文字替换,因此下面介绍指针参数和函数模板实现的类属函数。

2)用指针参数实现类属函数

#include
using namespace std;
//用指针参数实现类属的排序函数(框架)


void sort(
        
        //1.先定义一个void* 类型的形参base,使得它能够接受任意待排序数组的首地址
        void *base,
        //2.count参数用于获得数组元素的个数
        unsigned int count,
        //3.element_size用于每个数据元素的尺寸
        unsigned int element_size,
        //4.最后定义一个函数指针类型的形参cmp,它从调用者处获得一个函数,这个函数功能是比较两个数组元素的大小
        bool (*less_than)(const void*,const void*)
        
        ){
    
    //(1)取第i个元素,i从0到count-1,下面是第i个元素的首地址
    (char*)base+i*element_size;
    
    //(2)比较第i个和第j个元素的大小:首先分别计算i和J的首地址,然后调用cmp指向的函数来比较这两个地址上元素的大小
    (*less_than)(
            (char*)base+i*element_size,(char*)base+j*element_size
            )//传入i和j的地址
            
    
    //(3)交换i和j,逐个字节交换这两个地址上的元素
    char* p1=(char*)base+i*element_size;//p1是i的地址
    char* p2=(char*)base+j*element_size;//p2是j的地址

    for(int k=0;k 
  

-------------------------------------------------------------------------------------------------------------------------------

下面的程序片段是利用上面定义的排序函数分别对int、double、以及A类型的数组进行排序

//比较int类型的元素大小
bool int_less_than(const void* p1,const void* p2){
    if( *(int *)p1<*(int *)p2  )
        return true;
    else
        return false;
}


//比较double类型的元素大小
bool double_less_than(const void* p1,const void* p2){
    if( *(double *)p1<*(double *)p2  )
        return true;
    else
        return false;
}

//比较A类型的元素大小
bool A_less_than(const void* p1,const void* p2){
    if( *(A *)p1<*(A *)p2  )
        return true;
    else
        return false;
}

模板简要介绍,C++读书笔记_第1张图片

---------------------------------------------------------------------------------------------------------------------------------

用指针实现类属函数的不足之处在于:除了数组首地址和数组元素个数外,需要定义额外的参数(元素尺寸和比较函数),并且要进行大量的指针运算,这不仅使得实现比较麻烦,而且使得程序易读性差和容易出错。另外,用指针实现类属函数也不便于编译程序进行类型检查。。

3)用函数模板实现类属函数

C++中,实现类属函数的另外一种方法是用函数模板,function template是指带有类型参数的函数定义,格式如下:

template 
<返回值类型>  <函数名> (<形参列表>){
    ...
}

例子:

//用模板实现类属的排序函数框架
template //T是数组的元素类型,可以是int、double、A。。。
void sort(T elements[],unsigned int count){
    //取第i个元素
    elements[i];
    //比较第i个和第j个元素的大小
    elements[i]T temp=elements[i];
    elements[i]=elements[j];
    elements[j]=temp;
}//sort
...
int a[100];
sort(a,100);//对int类型数组进行排序
double b[200];
sort(b,200);//对double类型数组进行排序
A c[300];
sort(c,300);//对A类型数组进行排序

4)函数模板的实例化

  • 函数模板可以隐式实例化,也可以显式实例化
  • 类模板只能显式实例化

显式实例化格式:

//模板函数max的声明
template 
T max(T a,T b){
    
     return a>b?a:b;    
    
}
//模板函数max的调用(显式)
max(1.4,3.5);

5)除了类型参数外,模板也可以带有非类型参数

#include
using namespace std;

//第一个参数T是类型参数,取值为(int,double,float等),第二个参数是普通参数
//模板函数定义
template 
void function(T t){
    T temp[size];
}
//模板函数调用示例
int main(){
    function(8.9);
    //T类型为float,size为10的,参数为(float t)且取t=8.9的函数
   return 0;
}

(二)类模板

如果一个类的成员类型可变,则该类成为类属类。在C++中,类属类一般用类模板实现。

类模板(class template)是指带有类型参数的类定义

1)格式

template 
class <类名>{
    ...
};
//对于在类内声明,类外定义的成员函数,应采用如下格式
template 
<返回值类型> <类名>::<成员函数名>(<参数列表>){
    ...
}

2)类模板示例练习01(自己动手打一遍才能记住)

1.模板类的定义

//定义一个可以表示各种元素的Stack类
template 
class Stack{
    //private数据成员
    T array[100];//定义一个元素类型为T的,长度为100的数组array
    int top;
    //public功能函数
public:
    Stack(){ top=-1;}//构造函数
    void push(const T &x);//在类内声明,等一会需要再类外定义的成员函数,传入一个T类型的数据压入栈中
    void pop(T &x);//类型为T的元素x退栈
};

2.类外函数的定义

template 
void Stack::push(const T &x) {
    ...
}

template 
void Stack::pop(const T &x){
    ...
}

3.在main中使用该模板类的格式示例

//模板类调用示例
int main(){
   Stack S1;//T被实例化为int,创建了一个类的对象S1
   int x;
   S1.push(10);
   S1.pop(x);
    
   Stack S2;
   double y;
   S2.push(4.4);
   S2.pop(y);
   
   Stack  S3;
   A m,n;
   S3.push(m);
   S3.pop(n);
   
   return 0;
}

3)类模板示例练习02

1.模板类的定义

template //同时带有类型参数和非类型参数的模板类
class Stack{
    T array[size];//每个元素为T类型,大小为size的数据成员
    int top;
public:
    Stack(){ top=-1;}
    void push(const T &x);
    void pop(T &x);
};

2.类外函数的定义

template 
void Stack::push(const T &x){
    
}

template 
void Stack::pop(T &x){
    
}

3.在main中使用该模板类的格式示例

//模板类调用示例
int main(){
    
   Stack S1;//创建一个最多有100个int类型的元素所构成的Stack对象
   Stack S2;//创建一个最多有44个double类型的元素所构成的Stack对象

   return 0;
}

(三)类模板分文件编写(.h和.cpp)

1)第一种方式:直接包含源文件.cpp

原因:在.h中只有声明,对于模板类来说是没有创建的,所以编译器会找不到实例;假如直接“#include xx.cpp”由于该.cpp文件中已经包含了.h,所以代码是完整的。

2)第二种方式:(更常用)将源文件和头文件的内容写到一起,将后缀名改为.hpp

-------------------------------------------------------

  写在最后,这几天零零散散看了C++里面的模板和容器,因为这章比较难,看The Cherno就看不太懂了,视频换成了b站的黑马程序员,加上读教材,磨了好几天终于有一点点明白了,OK。因为宅家太穷又去打了5天零工,每天11点睡5点半起床,洗把脸就得骑车去卡点上班。然后,如果说Cherno的C++系列是适合有编程经验的精华教程,精灵密道,那么黑马就是适合小白提升能力的高速大马路。黑马的那个老师用的软件是什么不知道,就是看起来非常舒服,小巧便捷,启动快,截图如下,感觉学编程这样搞,整洁、有秩序、有逻辑,会让自己的认知加速。

模板简要介绍,C++读书笔记_第2张图片

你可能感兴趣的:(C++自学,c++,算法,开发语言)