泛函编程—模板函数_类模板

函数业务逻辑一样,只是函数参数类型不同
函数模板的本质:类型参数化——泛型编程

语法:

template <typename T>
template <class T1,class T2>多个参数类型
类型 函数名(形式参数表)
{
  语句序列;
}

函数模板基础:

template是告诉C++编译器,开始泛型编程,看到T,不要随便报错

template <typename T>//一个模板
void myswap(T& a, T& b)
{
  T c;
  c = a;
  a = b;
}
//调用时,显式说明类型
  myswap<int>(x,y);
  myswap<char>(x,y);
//自动类型推倒,尽量不要用
  myswap(x,y);

template <typename T1, typename T2>//两个模板,定义了一定要用
void myswap(T1& a, T2& b)
{

}

在使用模板时,遇到修改模板里面内容,需要清除原有方案,重新编译。

函数模板遇上函数重载:

//函数模板不允许自动类型转化,严格的类型匹配
//普通函数能够进行自动类型转化,在不失精度的前提下
1、函数模板可以像普通函数一样被重载
2、C++编译器优先考虑普通函数
3、如果函数模板可以产生一个更好的匹配,那么选择模板(比如在使用普通函数导致精度缺失的时候)
4、可以通过空模板实参列表的语法限定编译器只通过模板匹配

template <typename T>//一个模板
void myswap(T& a, T& b)
{
  T c;
  c = a;
  a = b;
}
//一个普通函数
void myswap(int& a, char& b)
{
  int c;
  c = a;
  a = b;
}
int a = 10;
char c = ‘c‘;
myswap(a,c) //调用普通函数
myswap(c,a) //调用普通函数,进行隐形类型转换
myswap(a,a) //调用模板函数,严格的类型匹配,不会进行类型转换;但是普通函数如果也有两个int形参时,优先普通函数,看下一个例子

//模板函数重载
int max(int a, int b)
{
  return a>b?a:b;
}
template<typename T>
T max(T a, T b)
{
  return a>b?a:b;
}
template<typename T>
T max(T a, T b, T c)
{
  return max(max(a,b), c);
}

int a = 1;
int b = 2;
max(a,b); //函数模板和普通函数都满足调用时,优先普通函数
max<>(a,b);//显示使用函数模板方法,则使用<>空的类型参数化列表
max(3.0,4.0);//类型一致,可以使用模板。且使用普通函数,失真,则调用函数模板
max(3.0,4.0,5.0);//函数模板可以重载
max(‘a‘,100);    //类型不一致,不能用函数模板,调用普通函数进行隐式类型转换

函数模板机制结论:

编译器并不是把函数模板处理成能够处理任意类的函数
函数模板通过具体类型产生不同的函数
编译器会对函数模板进行二次编译:
声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译

类模板:
解决问题:多个类功能一致,数据类型不同。
类模板用于实现类所需数据的类型参数化
类模板在表示数组、表、图等数据结构显得特别重要;
实现 数据结构 与 算法的分离,类模板可以使 链表类型存不同数据类型数据
类模板的定义和使用:

template <typename T>
class A
{
public:
  A(T a=0)
  {
    this->a = a;
  }
public:
  void printA()
  {
    cout << "a: " << a << endl;
  }
protected:
  T a;
}
int main()
{
  A<int> a1(10); //模板类是抽象的,需要进行类型具体化
  a1.printA();
  system("pause");
  return 0;
}

类模板做函数参数:

void useA(A<int>& b) //C++编译器要求具体的参数类
{
  b.printA();
}
  useA(a1);

继承中的类模板:

一、模板类派生普通类
子模板类派生时,需要具体化模板类,C++编译器需要知道父类的数据类型具体是什么
要知道父类所占内存大小,只有数据类型固定才知道如何分配内存

class B:public A<int>
{
public:
  B(int a=10, int b=20):A<int>(a) //使用初始化参数列表,初始化父类对象注意父类为模板类时,使用A<int>类类型具体化
  {
  this->b = b;
  }
protected:
private:
  int b;
}
  

B b1(1,2);

二、模板类派生模板类

template <typename T>
class C:public A<T> //基类为模板类型
{
public:
  C(T c, T a):A<T>(a) //基类为模板类型
  {
    this->c = c;
  }
void printC()
{
  cout << "c1: " << c << endl;
}
private:
  T c;
}
void main()
{
C<int>c1(1,2);
c1.printC();
system("pause");
}

模板类的函数重载:

友元函数只用于重载 输入输出流 << 和 >>
其余使用成员函数,成员函数需要在类中声明,而<<需要在ostream类中声明,但我们在C++源码中修改很麻烦,
所以,使用友元实现。友元函数只需要在需要使用的地方的类中定义ostream为该类的友元函数就可以了。

在模板类中写友元函数和成员函数重载的方法:
1、所有函数声明实现都写在.h文件的内部就可以啦(简单)
2、声明和实现分开,但都在一个.cpp内
函数提出来的时候,参数类型、类作用域、返回值注意使用<T>
友元函数:只用于输入输出流

类内声明:friend ostream& operator<< <T> (ostream& out, Complex &c3); //友元函数声明有<T>
类外实现:template<typename T>
ostream& operator<<(ostream& out, Complex<T>& c3) //友元函数是全局函数,不需要类的作用域
{

}

template<typename T>
成员函数:

类内声明: Complex operator+(Complex &c2); //正常写就可以啦
类外定义:主要三要素
Complex<T> Complex<T>::operator+(Complex<T>& c2)
{
  Complex tem(a+c2.a,b+c2.b);
  return tem;
}

除了输入输出流使用友元函数重载,其余最好使用成员函数重载,不然处理起来很麻烦。。。

3、.h和.hpp分开,其他类使用,要包含.hpp(不是.cpp)
这个时候和情况2差不多,滥用友元函数容易出问题。

模板类中的static关键字,不同的调用类型,static关键字属于不同的类,这是由模板的实现机制决定的。

static是属于具体类的。

时间: 2024-12-14 20:50:59

泛函编程—模板函数_类模板的相关文章

C++模板编程 - 第三章 类模板

模板类 template<typename T> stack {...} 的构造函数应该写作stack而不是stack<T>,经作者这么一说我在注意到这件事情. 模板的特化 先说说函数模板.函数模板只能全特化,不能偏特化,并且特化的模板函数相比于等价模板函数优先,但是和非模板函数相比非模板函数优先. 1 #include<iostream> 2 3 using std::cout; 4 using std::endl; 5 6 // version 1 7 int ma

函数、类模板

泛型程序设计 算法实现时不指定具体要操作的数据的类型.适用于多种数据结构. 函数模板 Template <class 类型参数1,class类型参数2,…..> 返回值类型 模板名(形参表) { 函数体: } 函数模板可以重载,只要它们的形参表不同即可. C++编译器遵循以下优先顺序: 先找参数完全匹配的普通函数(非由模板实例化而得的函数) 再找参数完全匹配的模板函数 再找实参经过自动类型转换后能匹配的普通函数 上面的都不符合则报错. 可以在函数模板中使用多个类型参数,可以避免二义性. #in

3.2 STL中的函数对象类模板

*: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. 2)less是STL中最常用的函数对象类模板,其定义如下: template<class _Tp> struct less { bool oprator()(const _Tp&_x,const _Tp&_y)const { return _c<_y; } } 要判断两个i

类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

 1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPushButton> #include <QLabel> template<class T> class run { public: T w; void show() { w.show(); } void settext() { w.setText("A"); }

C++ Primer 学习笔记_80_模板与泛型编程 --类模板成员

模板与泛型编程 --类模板成员 引言: 这一节我们介绍怎样实现前面提到的Queue模板类. 标准库将queue实现为其他容器之上的适配器.为了强调在使用低级数据结构中设计的编程要点,我们将Queue实现为链表.实际上,在我们的实现中使用标准库可能是个更好的决定!!-_-. 1.Queue的实现策略 如图所示,我们实现两个类: 1)QueueItem类表示Queue的链表中的节点,该类有两个数据成员item和next: a. item保存Queue中元素的值,它的类型随Queue的每个实例而变化:

C++ Primer 学习笔记_81_模板与泛型编程 --类模板成员[续1]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height

C++ Primer 学习笔记_82_模板与泛型编程 --类模板成员[续2]

模板与泛型编程 --类模板成员[续2] 六.完整的Queue类 Queue的完整定义: template <typename Type> class Queue; template <typename Type> ostream &operator<<(ostream &,const Queue<Type> &); template <typename Type> class QueueItem { friend clas

【C++】模板简述(三):类模板

上文简述了C++模板中的函数模板的格式.实例.形参.重载.特化及参数推演,本文主要介绍类模板. 一.类模板格式 类模板也是C++中模板的一种,其格式如下: template<class 形参名1, class 形参名2, ...class 形参名n> class 类名{ ... }; 例如:我个人模拟实现的Vector的声明 template<typename T> class Vector{ public: typedef T* Iterator; //迭代器 typedef c

C++ Primer 学习笔记_82_模板与泛型编程 -类模板成员[续二]

模板与泛型编程 --类模板成员[续2] 六.完整的Queue类 Queue的完整定义: template <typename Type> class Queue; template <typename Type> ostream &operator<<(ostream &,const Queue<Type> &); template <typename Type> class QueueItem { friend clas