C++模板

本文详细介绍了C++中的泛型编程,重点讲解了函数模板和类模板的使用,包括模板的基本语法、自动类型推导、模板特化以及类模板的成员函数实现。此外,还探讨了模板在函数重载中的选择规则、类模板与继承的关系以及类模板成员函数的类外实现。同时,文章提到了模板的局限性和如何通过模板特化解决特定类型的问题。
摘要由CSDN通过智能技术生成

泛型编程:利用模板的一种技术进行实现。

(一)基本概述

模板是建立通用的模具,大大提高复用性。模板不可以直接使用,它只是一个框架。通用但不是万能。

C++中的模板分为函数模板和类模板。

函数模板的语法:建立一个通用的函数,其返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。template<typename T>

template-->声明创建模板

typename-->表面其后面的数据类型是一种数据类型,可以用class代替。

T-->通用的数据类型,名称可以替换,通常为大写字母

void swapint(int &a,int &b)
{
  int t=a;
  a=b;
  b=t;
}

void swapdouble(double &a,double &b)
{
  double t=a;
  a=b;
  b=t;
}

//函数模板:
template<typename T>//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错。T是一个通用的数据类型

void myswap(T &a,T &b)
{
  T temp=a;
   a=b;
   b=temp;
}

利用函数模板交换:

1)显示指定类型
myswap<int>(a,b);

2) 自动类型推导
myswao(a,b);

函数模板注意事项:

1)自动类型推导,必须推导出一致的数据类型T才可以使用

2)模板必须要确定T 的数据类型,才可以使用

template<class T>==template<Typename T>

void myswap(T&a,T&b)
{
  T temp=a;
  a=b;
  b=temp;
}

void test01()
{
  int a=10;
  int b=20;
  myswap(a.b);//自动类型匹配
};

template<class T>
void func()
{
  cout<<"调用”<<endl;
}

void test01{
   func<int>();//模板必须要确定数据类型,才可以使用
}

(二)函数模板案例:利用模板对不同类型的数据进行排序

template<typename T>
void mysort(T arr[].int len)
{
  for(int i=0;i<len-1;i++)
  {
     max=i;
    for(j=0;j<len;j++)
     {
        if(a[j]>max) max=j;
     }
     if(max!=i)
      swap(arr,max,i);
  }
}

普通函数和函数模板的区别:

普通函数使用的时候可以发生自动类型转换(隐式类型转换)

函数模板调用的时候,如果利用自动类型推导,不会发生 隐式类型转换

如果利用显示指定类型的方式,可以发生隐式类型转换

int add(int a,int b)
{
 return a+b;
}

void test{
 int a=10;
 char c='c';
 cout<<add(a,c)<<endl;//输出109
 }
template<class T>
T myadd(T a,T b)
{
  return a+b;
}

void test02()
{
 cout<<myadd(a,c)<<endl;//err
 cout<<myadd<int>(a,c)<<endl;//right
}

调用规则:

如果普通函数和函数模板都可以实现,优先使用普通函数。

(当只有一个普通函数的声明的时候会报错)

都可以通过空模板参数列表来强调函数模板。

myPrint<>(a,b);

函数模板也可以发生重载。

如果函数模板可以产生更好的匹配,优先调用函数模板。

void myprint(int a,int b)
{
  cout<<“调用的普通函数”<<endl;
}

template<class T>
void myprint(T a,T b)
{
 cout<<"调用的模板"<<endl;
}

(三)模板的局限性

比如有的时候传入的是类似person的具体数据类型,无法正常运行。C++为此提供模板的重载,为这些特定的类型提供具体的模板。

class person{
 public:
  person(string name,int age)
  {
   this->m_name=name;
   this->m_age=age;
  }
   string m_name;
   int m_age;
};

template<class T>
bool mycompare(T &a,T &b)
{
   if(a==b)
     return ture;
   else 
     return false;
}
//利用具体化的person版本实现代码,具体化优先调用
template<>bool mycompare(person &p1,person &p2)

void test02()
{
 person p1("mm",18);
 person p2("tt",19);

 bool ret=mycompare(p1,p2);
 if(ret)
  { 
    cout<<"p1==p2"<<endl;
  }
else
 {
  cout<<"p1!=p2"<<endl;
 }
}

(四)类模板:

作用:建立一个通用的类,类中的成员和类型不具体确定,用一个虚拟的类型来代表。

template<Typename T>
类

template--声明创建模板

typename--表明其后面的符号是一种数据类型,可以用class代替

T--通用的数据类型,名称可以替换,通常为大写字母

template<class NameType,class AgeType>
class person
{
public:
   person(NameType name,AgeType age)
   {
      this->m_age=age;
      this->m_name=name;
   }

  void showperson()
  {
   cout<<this->m_Name<<endl;
  }

   NameType m_name;
   AgeType m_age;
};

void test01()
{
  person<string,int>p1("孙悟空",999);//只能用显示指定类型
  p1.showperson();
}

类模板和函数模板的区别:

类模板中没有自动类型推导的使用方式+类模板在模板参数列表中可以有默认参数 

class person
{
public:
   person(NameType name,AgeType age=int)
   {
      this->m_age=age;
      this->m_name=name;
   }

  void showperson()
  {
   cout<<this->m_Name<<endl;
  }

   NameType m_name;
   AgeType m_age;
};

类模板中成员函数的创建时机:普通类中的成员函数一开始就创建了,类模板中的成员函数在调用的时候再创建。 

(五)类模板对象作为参数:

template<class T1,class T2>
class person
{
public:

  person(T1 name,T2 age)
  {
    this->m_Name=name;
    this->m_age=age;
  }

  void showperson()
  {
    cout<<this->m_Name<<this->m_age<<endl;
  }

  T1 m_Name;
  T2 m_age;
};

void test01()
{
  person<string,int>p("孙悟空",100);
  showperson(p);
}

1)指定传入的类型——直接显示对象的数据类型

void printperson(Person<string,int>&p)
{
  p.showperson();
}

2)参数模板化——将对象中的参数变为模板进行传递

template<class T1,class T2>
void printperson(Person<T1,T2>&p)
{
  p.showperson();
  cout<<"T1的类型为"<<typeid(T1).name()<<endl;
}

3)整个类模板化——将这个对象类型 模板化进行传递

template<class T>
void printperson(T &p)
{
  p.showperson();
}

(六)类模板与继承:

1)当子类继承的父类是一个类模板的时候,子类在声明的时候,要指出父类中T的类型

template<class T>
class base
{
   T m;
};

class son:public base<int>
{

};

2)如果不确定,编译器无法为子类分配内存

3)如果想要灵活地指出父类中T的类型,子类也要变成类模板

template<class T1,class T2>
class son2:public base<T2>
{
  T1.obj;
};

类模板成员函数的类外实现:

template<class T1,class T2>
class person
{
public:

  person(T1 name,T2 age);
  void showperson();
 
  T1 m_Name;
  T2 m_age;
};

template<class T1,class T2>
person<T1,T2>:: person(T1 name,T2 age)
{
  
    this->m_Name=name;
    this->m_age=age;

}

 void person<T1,T2>:: showperson()
{
    cout<<this->m_Name<<this->m_age<<endl;
}

(七)类模板的分文件编写

问题:类模板的成员函数创建时机是在调用阶段,会导致分文件编写的时候链接不到

解决方法:

直接包含cpp源文件//不能用.h

将声明和实现(.h和.cpp)写到同一个文件中,并且更改后缀名为hop.hop是约定的名称而不是强制的。

类模板和友元:

掌握类模板配合友元函数的类内和类外实现。

全局函数类内实现:直接在类内声明友元 全局函数的类外实现:需要提前让编译器直到全局函数的存在。

//全局函数 类内实现

friend void showperson(person<T1,T2>P)
{
  cout<<p.m_name<<p.m_age<<endl;
}
类内:加空模板参数列表
friend void showperson<>(person<T1,T2>p)

全局函数类外实现
template<class T1,class T2>
void showperson(person<T1,T2>,p)
 {
    cout<<p.m_name<<endl;
 }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太一TT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值