C++提高编程-模板
模板的基本概念
模板的主要用于提高C++的泛型编程而设计的,可以把模板理解为通用的模具,大大提高复用性,这和字面意思也差不多。
函数模板
函数模板基本概念

template<typename T> //typename可以替换成class
写函数,其中变量用T表示
实例代码如下:
//函数模板语法如下
//声明的意义在于告诉编译器,紧跟的函数中的T不要报错,为泛型
template<typename T>
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
//模板使用方法如下
//1.自动类型推导
Swap(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
//2.显示告知
Swap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
使用函数模板时,必须确定出通用数据类型T,并且能够推导出一致的类型。
普通函数和函数模板的区别

示例代码如下:
//普通函数
int add(int a, int b)
{
return a + b;
}
//函数模板
template<typename T>
int myAdd(T a, T b)
{
return a + b;
}
void test01()
{
int a = 10;
int b = 20;
char c = 'a';
//普通函数可以隐式类型转换
cout << add(a, c) << endl;
//模板函数自动类型推导,无法进行隐式类型转换
//cout << myAdd(a, c) << endl;
//模板函数显示指定类型,可以进行隐式类型转换
cout << myAdd<int>(a, c) << endl;
}
普通函数和函数模板的区别

实例代码如下:
//普通函数和函数模板调用规则
//1.如果函数模板和普通函数都可以调用,优先调用普通函数
//2.可以通过空模板参数列表 强制调用函数模板
//3.函数模板可以发生函数重载
//4.如果函数模板可以产生更好的匹配,优先调用函数模板
//普通函数
void myPrint(int a, int b)
{
cout << "调用普通函数" << endl;
}
//函数模板
template<typename T>
void myPrint(T a, T b)
{
cout << "调用函数模板" << endl;
}
//函数模板可以发生重载
template<typename T>
void myPrint(T a)
{
cout << "调用重载的函数模板" << endl;
}
void test01()
{
int a = 10;
int b = 20;
//都可以调用时,优先调用普通函数
myPrint(a, b);
//通过空模板参数列表,强制调用模板
myPrint<>(a, b);
myPrint<int>(a, b);
//函数模板可以发生承载
myPrint(a);
//如果函数模板可以产生更好的匹配,优先调用函数模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1, c2);
}
模板局限性
示例代码如下:
//模板局限性
//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
//1.第一种方法,可以采用重载运算符的方法实现.
/*bool operator==(const Person& p)
{
if (this->m_Age == p.m_Age && this->m_Name == p.m_Name)
return true;
return false;
}*/
string m_Name;
int m_Age;
};
//对比两个数据是否相等
template<typename T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
return false;
}
//2,第二种解决办法,对模板具体化,优先调用
template<> bool myCompare(Person& a, Person& b)
{
if (a.m_Age == b.m_Age && a.m_Name == b.m_Name)
return true;
return false;
}
void test01()
{
Person p1("Tom", 12);
Person p2("Tom", 12);
bool ret = myCompare(p1, p2);
if (ret)
{
cout << "p1 == p2" << endl;
}
else
{
cout << "p1 != p2" << endl;
}
}
类模板
类模板语法

示例代码如下:
//类模板
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_Age = age;
this->m_Name = name;
}
void show_Person()
{
cout << this->m_Name << ' ' << this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
Person<string,int> p1("孙悟空", 999);
p1.show_Person();
}
类模板和函数模板的区别
示例代码如下:
//类模板和函数模板的区别
//1.类模板没有自动类型推导
//2.类模板参数列表中可以有默认参数
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_Age = age;
this->m_Name = name;
}
void show_Person()
{
cout << this->m_Name << ' ' << this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
//Person p1("孙悟空", 999); //错误,类模板没有自动类型推导
Person <string>p("猪八戒", 1888);
p.show_Person();
}
类模板中成员函数创建时机

很好理解,创建时,并不知道类模板中参数类型,所以函数中并不知道参数,无法有效的调用。
当调用函数时,才知道参数列表,这时才会创建函数。
类模板对象作为函数参数
示例代码如下:
//类模板对象做函数参数
template<class T1, class T2>
class Person
{
public:
Person(T1 age,T2 name)
{
this->m_Age = age;
this->m_Name = name;
}
void showPerson()
{
cout << this->m_Name << " " << this->m_Age << endl;
}
T1 m_Age;
T2 m_Name;
};
//1.指定参数传入类型
void printPerson(Person<int,string> &p)
{
p.showPerson();
}
//2.参数模板化(感觉和函数模板没啥区别嘞)
template<typename T1,typename T2>
void printPerson2(Person<T1, T2>& p)
{
p.showPerson();
cout << "T1的推导参数类型为:" << typeid(T1).name() << endl;
cout << "T1的推导参数类型为:" << typeid(T2).name() << endl;
}
//3.整个类模板化
template<typename T>
void printPerson3(T& p)
{
p.showPerson();
cout << "T的数据类型为:" << typeid(T).name() << endl;
}
void test01()
{
Person<int, string>p1(11, "孙悟空");
printPerson(p1);
Person<int, string>p2(18, "猪八戒");
printPerson2(p2);
Person<int, string>p3(21, "沙和尚");
printPerson3(p3);
}
类模板与继承
示例代码如下:
//类模板与继承
template<class T>
class Base
{
T m;
};
//1.子类继承类模板时,必须指明父类的参数类型
class Son : public Base<int>
{
int m;
};
//2.如果想要灵活指定父类中的T类型的话,子类也需要编程类模板
template<class T>
class Son1 : public Base<T>
{
T m;
};
模板类外实现成员函数
//模板类,类外外实现成员函数
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void show_Person();
T1 m_Name;
T2 m_Age;
};
//类外实现构造函数
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
//类外实现普通成员函数
template<class T1,class T2>
void Person<T1, T2>::show_Person()
{
cout << this->m_Name << ' ' << this->m_Age << endl;
}
void test01()
{
Person<string, int> p("张三", 18);
p.show_Person();
}
类模板的分文件编写
正常情况下,类模板的分文件编写应该如下:
Person.h文件代码如下:
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void show_Person();
T1 m_Name;
T2 m_Age;
};
Person.cpp文件代码如下:
#pragma once
#include "person.h"
//类外实现构造函数
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
//类外实现普通成员函数
template<class T1, class T2>
void Person<T1, T2>::show_Person()
{
cout << this->m_Name << ' ' << this->m_Age << endl;
}
然后在要使用的文件中加上#include "Person.h"语句,即可正常调用,但发现出现问题,因为在之前提到过,类模板的成员函数创建时机是调用时才创建,所以在链接阶段,源文件中只包含了.h文件,虽然.h文件中有函数的声明,但成员函数由于未调用,所以并没有链接到这些成员函数,这样就无法调用。
解决办法一:直接在要使用的文件中加上#include"Person.cpp"语句。
解决办法二:将.h和.cpp文件合并,后缀名改为.hpp文件,包含.hpp文件即可。
类模板与友元
示例代码如下:
//将类的声明提前,方便接下来函数的实现
template<class T1, class T2>
class Person;
//需要将函数实现提前到函数前,由于声明中有Person,所以还需将Person类的声明你提起按
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
cout << "类外实现友元全局函数 " << p.m_Name << ' ' << p.m_Age << endl;
}
template<class T1, class T2>
class Person
{
//友元全局函数,类内实现
friend void printPerson(Person<T1, T2>& p)
{
cout << "类内实现友元全局函数 " << p.m_Name << ' ' << p.m_Age << endl;
}
//友元全局函数,类外实现
//为了声明这是全局函数,这里需要加上<>,参数列表
friend void printPerson2<>(Person<T1, T2>& p);
public:
Person(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
private:
T1 m_Name;
T2 m_Age;
};
void test01()
{
Person<string, int> p("张三", 18);
printPerson(p);
printPerson2(p);
}

浙公网安备 33010602011771号