函数模板

模板概念及语法

  主要目的,简化代码,减少重复代码。基本语法格式:  template<class T> 或者 template<typename T> //末尾不加分号

 template <class T> //等价于 template <typename T>

 void mySwap(T &a, T &b){
T tmp = b;
b = a;
a = tmp;
} void test02(){
int a = , b = ;
//自动推导类型,里面必须有参数,而且参数类型必须相同,因为两者是同一个类型T,这也是类型参数化的意义
mySwap(a, b);
//显式调用,显式指定类型
mySwap<int>(a, b); cout << "a = " << a << "b = " << b << endl;
}

函数模板与普通函数 

1.与类模板区别

  template声明下面是函数定义,则为函数模板,否则为类模板。注意:每个函数模板前必须有且仅有一个template声明,不允许多个template声明后只有一个函数模板,也不允许一个template声明后有多个函数模板。

2. 与普通函数的区别

  (1)函数模板不可以进行隐式类型转换,普通函数可以进行隐式类型转换;

  (2)两者的调用规则:

    ①若函数模板和普通函数出现了重载(两者仅仅参数类型不同,一个为T,一个为具体类型),优先使用普通函数调用,若普通函数没有实现,则会出现“无法解析命令”的错误,不会因此而调用函数模板;

    ②如果想强制调用模板,可以使用空函数列表

    ③函数模板可以发生重载(参数类型和个数等)

    ④如果函数模板可以更好的匹配,优先调用函数模板,如果函数模板和普通函数都能匹配,优先调用普通函数(这一点和①类似)。

3. 模板机制剖析

  (1)模板不是万能的,不能处理所有的数据;

  (2)函数模板不可以直接调用,需要编译器处理成模板函数后才能调用;

  (3)编译器对函数模板进行两次编译,一次是在声明的地方对模板代码(函数模板)进行编译,一次对调用时对参数替换后的代码(模板函数)进行编译。

 template <class T>
bool myComp(T &a, T &b){ cout << "模板函数调用" << endl;
if (a == b)
return true;
else
return false;
} //函数模板重载
template <class T>
bool myComp(T &a, T &b, T &c){ cout << "模板函数调用" << endl;
if (a == b == c)
return true;
else
return false;
} ////如果int类型的参数调用上述函数模板,会替换参数类型处理为模板函数如下
//bool myComp(int &a, int &b){
// if (a == b)
// return true;
// else
// return false;
//} bool myComp(int a, int b){ cout << "普通函数调用" << endl; if (a == b)
return true;
else
return false;
} void test02(){
int a = , b = , c = ;
float d = ; //普通函数和模板函数都可以匹配,优先调用普通函数
myComp(a, b);
//普通函数中形参可以隐式转换(隐式强转),函数模板不可以
myComp(a, d);
}

4. 函数模板的局限性

  (1)模板不能解决所有数据类型;

  (2)如果出现不能解决的类型,可以通过数据类型具体化来满足要求;

  (3)数据类型具体化语法: template <> 返回值 函数名 <具体类型> (参数) ,将数据类型具体化,仅仅是数据类型,不能修改返回值类型和函数名。

  (4)当具体化和参数化同时匹配时,优先使用具体化

 class Person{
public:
Person(string name, int age){
m_Name = name;
m_Age = age;
} string m_Name;
int m_Age; }; template <class T>
bool myComp(T &a, T &b){
if (a == b)
return true;
else
return false;
} //自定义数据无法适应模板,会报如下错误
//error C2678: 二进制“==”: 没有找到接受“Person”类型的左操作数的运算符(或没有可接受的转换)
//另外,将数据类型具体化,仅仅是数据类型,不能修改返回值类型和函数名
template<> bool myComp<Person>(Person &a, Person &b){
if (a.m_Age == b.m_Age){
return true;
}
else
return false;
} void test02(){
int a = , b = ;
int ret = myComp(a, b);
cout << "ret = " << ret << endl; Person p1("tom", );
Person p2("jerry", );
int ret1 = myComp(p1, p2); cout << "ret = " << ret1 << endl;
}

类模板

1. 基本使用

  与函数模板相同,紧跟在template声明后,同样一个template对应一个类模板。

  与函数模板的区别:(1)类模板不支持自动类型推导;(2)数据类型可以有默认参数.

 //类模板可以有默认参数
//template<class NameType, class AgeType = int>
template<class NameType, class AgeType>
class Person{
public:
Person(NameType name, AgeType age){
m_Name = name;
m_Age = age;
} NameType m_Name;
AgeType m_Age;
}; void test02(){
//类模板不支持自动类型推导
//缺少 类模板 "Person" 的参数列表
//Person p("啊呀呀", 10); Person<string, int> p("啊呀呀", );
}

2. 成员函数创建时机

  成员函数只有在编译或运行时才会创建,仅仅写出来不会报错,如示例所示

 class Person1{
public:
void showPerson1(){
cout << "Person1调用" << endl;
}
}; class Person2{
public:
void showPerson2(){
cout << "Person2调用" << endl;
}
}; template<class T>
class myclass{
public:
T obj; void func1(){
obj.showPerson1();
} void func2(){
obj.showPerson2();
}
}; void test02(){
myclass<Person1>tmp; tmp.func1(); //成员函数只有在程序编译或运行时才会创建,只是写出来不会报错,在编译或运行时会报错
//tmp.func2();
}

3. 类模板作函数的参数

  有三种方式:(1)显示指定类型;(2)参数模板化;(3)整体模板化

 template<class NameType, class AgeType>
class Person{
public:
Person(NameType name, AgeType age){
m_Name = name;
m_Age = age;
} void showPerson(){
cout << "name: " << this->m_Name << " age: " << this->m_Age << endl;
} NameType m_Name;
AgeType m_Age;
}; //1.显式指定类型
void doWork(Person<string, int> &p){
p.showPerson();
} //2.参数模板化
template<class NameType, class AgeType>
void doWork2(Person<NameType, AgeType> &p){
p.showPerson();
} //3.整体模板化
template<class PersonType>
void doWork3(PersonType &p){
p.showPerson();
} void test02(){
Person<string, int>p("tom", );;
doWork(p);
doWork2(p);
doWork3(p);
}

4. 继承中的类模板

  如果基类是模板类,则子类需要告诉编译器基类中的T是什么类型,如果不告诉编译器无法通过,不能分配内存。

 template<class T>
class Person{
public:
T m_Age;
};
//如果子类不显式标明父类中模板的数据类型,会报错:缺少类模板的参数列表
class Son :public Person<int>{ }; //子类中标明的数据类型也可以是模板
template<class T1, class T2>
class Son1 :public Person<T2>{
T1 m_name;
}; void test02(){
Son1<string, int>son; //标明Person类中的T为int型,T1为string
}

5. 类模板下的类外成员函数实现

  普通的类外成员函数实现时,需要将作用域写上即可,但在类模板下,需要将作用域写为类模板形式。另外在类外实现时,需要在类内声明。

 template<class T1, class T2>
class Person{
public:
//类内实现
Person(T1 name, T2 age;
//{
// this->m_Name = name;
// this->m_Age = age;
//} void showPerson();
//{
// cout << "name: " << this->m_Name << "age: " << this->m_Age << endl;
//} 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;
} template<class T1, class T2>
void Person<T1, T2>::showPerson(){
cout << "name: " << this->m_Name << "age: " << this->m_Age << endl;
} void test02(){
Person<string, int>p("tom", );
p.showPerson();
}

6. 类模板分文件编写问题

  一般进行分文件编写时,.h,.cpp分别写声明和实现,但是由于类模板的成员函数运行阶段才去创建,导致包含.h头文件,不会创建函数的实现,无法解析外部命令,此时

建议类模板不要分文件编写,写到一个类中即可,类内进行声明和实现,最后文件后缀改为hpp.

类模板下的友元函数

1. 类内友元函数实现

  类内友元函数实现, friend void printPerson(Person<T1, T2> &p)

 template<class T1, class T2>
class Person{
//友元函数遇到类模板,在类内实现
friend void printPerson(Person<T1, T2> &p){
cout << "name : " << p.m_Name << " age :" <<p.m_Age<< endl;
} public:
Person(T1 name, T2 age){
this->m_Name = name;
this->m_Age = age;
} T1 m_Name;
T2 m_Age;
}; void test02(){
Person<string, int> p("tom", );
printPerson(p);
}

2. 类外友元函数实现

  类外实现时,需要在类内通过空参数列表,告诉编译器,这是模板函数的声明,不加<>表示普通函数声明。另外,需要让编译器提前看到函数及类的声明。

 template<class T1, class T2>
class Person; //让编译器提前看到printPerson声明,但里面有Person声明,需要提前声明Person类
template<class T1, class T2>
void printPerson(Person<T1, T2> &p); template<class T1, class T2>
class Person{
//友元函数类外实现时,需要在类内通过空参数列表,告诉编译器,这是模板函数的声明
friend void printPerson<>(Person<T1, T2> &p);
//{
//cout << "name : " << p.m_Name << " age :" <<p.m_Age<< endl;
//} public:
Person(T1 name, T2 age){
this->m_Name = name;
this->m_Age = age;
} T1 m_Name;
T2 m_Age;
}; template<class T1, class T2>
void printPerson(Person<T1, T2> &p){
cout << "name : " << p.m_Name << " age :" << p.m_Age << endl;
} void test02(){
Person<string, int> p("tom", );
printPerson(p);
}

C++函数模板&类模板的更多相关文章

  1. 3.2 STL中的函数对象类模板

    *: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...

  2. C++ - 模板类模板成员函数(member function template)隐式处理(implicit)变化

    模板类模板成员函数(member function template)隐式处理(implicit)变化 本文地址: http://blog.csdn.net/caroline_wendy/articl ...

  3. C++ 函数模板&类模板详解

    在 C++ 中,模板分为函数模板和类模板两种.函数模板是用于生成函数的,类模板则是用于生成类的. 函数模板&模板函数     类模板&模板类  必须区分概念 函数模板是模板,模板函数时 ...

  4. C++ 函数模板/类模板

    #include <iostream> #include <vector> using namespace std; template < class T > // ...

  5. 函数模板&类模板

    #include <iostream> #if 0//函数模板 template<typename T> T max(T a, T b, T c)//函数模板 { if (a ...

  6. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  7. 类模板语法知识体系梳理(包含大量常犯错误demo,尤其滥用友元函数的错误)

    demo 1 #include <iostream> #include <cstdio> using namespace std; //template <typenam ...

  8. C++复习:函数模板和类模板

    前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...

  9. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

随机推荐

  1. 剑指offer——15剪绳子

    题目描述 给你一根长度为n的绳子,请把绳子剪成m段(m.n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m].请问k[0]xk[1]x...xk[m]可能 ...

  2. nutch二次开发环境搭建

    开发环境: ubuntu14.04 + jdk1.7 + eclispe +nutch1.7 1:解压下好nutch1.7 src 源码(wget http://archive.apache.org/ ...

  3. HDU 2874 /// tarjan离线求森林里两点的距离

    题目大意: 在一个森林里 询问 u v 两点 若不能到达输出 "Not connected" 否则输出两点距离 https://blog.csdn.net/keyboarderqq ...

  4. JDBC_事务说明

    JDBC控制事务:1.事务:一个包含多个步骤的业务操作,如果这个业务操作被事务管理则多个步骤同时成功或同时失败2.操作: 1.开启事务 2.提交事务 3.回滚事务3.使用Connection对象来管理 ...

  5. maven中报错Missing artifact com.oracle:ojdbc14:jar:10.2.0.4.0

    在检索完工程后报错Missing artifact com.oracle:ojdbc14:jar:10.2.0.4.0. 由于oracle的ojdbc收费,所以在maven项目导入时没有ojdbc14 ...

  6. Activiti学习笔记7 — ReceiveTask机器自动任务的使用

    一. 创建流程规则,如下图 二.发布流程 /** * 2.发布一个流程 */ @Test public void testDeployProcess() { RepositoryService rep ...

  7. redis通过命令传参以及主从复制

    config set appendonly  yes  临时生效 如果想永久生效的话,执行 config rewrite 并不是所有的都支持修改 config set bind ip  修改bind参 ...

  8. [转]SpringMVC框架入门配置 IDEA下搭建Maven项目

    初衷:本人初学SpringMVC的时候遇到各种稀奇古怪的问题,网上各种技术论坛上的帖子又参差不齐,难以一步到位达到配置好的效果,这里我将我配置的总结写到这里供大家初学SpringMVC的同僚们共同学习 ...

  9. 计算几何——直线交点poj1269

    求直线交点还是要推一个公式的.. 见博客https://blog.csdn.net/u013050857/article/details/40923789 还要学一下向量的定点比分法 另外poj精度好 ...

  10. react diff 极简版

    为什么react这么快呢 ? 因为react用了虚拟DOM: 但是每次虚拟DOM转真实DOM不也是很浪费性能吗 ? nice,所以关键点在Diff算法这里,去对比新旧DOM树,而后通过补丁去更新到真实 ...