函数模板基本语法
ini
void swapInt(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
void swapDouble(Double &a, Double &b){
Double temp = a;
a = b;
b = temp;
}
//定义模板 T通用数据类型
template<typename T>
void swapNum(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
test01(){
//call template method
//1,Automatic type derivation
int a = 1;
int b = 2;
swapNum(a, b);
//2,Display specified type
swapNum<int>(a, b);
}
函数模板注意事项
在template 中typename可以被替换为class。
template定义模板类型后紧随其后的是使用该模板的函数。该函数必须包含T类型的形参列表 。对于自动类型推导,传参必须能够推导出一致的数据类型T才可以使用。
ini
template<typename M>
void swap(M& a, M& b) {
M temp = a;
a = b;
b = temp;
}
void func() {
std::cout << "this is a func" << std::endl;
}
void test(){
int a = 10;
int b = 20;
swap(a, b);
func();
}
排序函数模板化
std::sort
能够实现自动推导类型 的原因是因为它是一个 模板函数 ,并且 C++ 使用了 模板类型推导(Template Type Deduction) 机制。模板函数允许根据传入的参数类型自动推导出函数模板的具体类型,这使得 std::sort
能够适应不同类型的容器和元素,而无需显式指定模板参数。
普通函数与模板函数的区别
普通函数 和模板函数的指定类型推导可以进行隐式类型转换,模板函数的自动类型推导则不行。
css
int myadd01(int a, int b){
return a+b;
}
template<typename T>
T myadd02(T a,T b){
return a+b;
}
void test(){
int a = 1;
int b = 2;
char c = 'c';
myadd01 (a , b);
myadd01 (a , c);
myadd02(a,b);
(x)myadd02(a,c);
myadd02<int>(a,c);
}
函数模板的调用规则
1,普通函数和函数模板都能实现的情况下,优先调用普通函数
2,可以通过指定空模板类型推导,强行调用函数模板
3,函数模板也可以发生重载
4,如果函数模板可以产生容易匹配(不需要隐式转换),则会优先调用函数模板,例如在4演示代码中,调用普通函数需要进行隐式转换,而直接传参与模板匹配可以避免发生转换
c
void myPrint(int a, int b) {
cout << "Call Normal Func";
}
template <typename C>
void myPrint(C a, C b) {
cout << "Call template";
}
template <typename C>
void myPrint(C a, C b, C c) {
cout << "Call template overload";
}
void test0001() {
int a = 10;
int b = 10;
//1
myPrint(a, b);
cout << endl;
//2
myPrint<>(a, b);
cout << endl;
//3
int c = 10;
myPrint(a, b, c);
cout << endl;
//4
char c1 = 'c';
char c2 = 'd';
myPrint(c1, c2);
}
int main() {
test0001();
}
函数模板局限性
函数模板并非万能,在处理一些自定义数据类型的操作时,我们需要具体化模板。
例如进行类对象之间的比较时,我们或者进行类内运算符重载,或者进行模板具体化,否则不能正常进行比较。
csharp
Overload is calling
not
Overload is calling
equel
test Match ================
Specific is calling
equel
class Person {
public:
int age;
string name;
Person(int age, string name) {
this->age = age;
this->name = name;
}
bool operator==(Person &p1) {
cout << "Overload is calling" << endl;
if (this->age == p1.age && this->name == p1.name) {
return true;
}
else {
return false;
}
}
};
template <typename T>
bool match(T &p1, T &p2) {
if (p1 == p2) {
return true;
}
else {
return false;
}
}
template<> bool match(Person &p1, Person &p2) {
cout << "Specific is calling" << endl;
if (p1.age == p2.age && p1.name == p2.name) {
return true;
}
else {
return false;
}
}
void result(bool res) {
if (res) {
cout << "equel";
}
else {
cout << "not";
}
cout << endl;
}
void testL() {
Person Tom(13, "Tom");
Person Tom2(13, "Tom");
Person Amy(14, "Amy");
bool res = (Tom == Amy);
result(res);
bool res2 = (Tom == Tom2);
result(res2);
cout << "test Match ================" << endl;
bool res3 = match(Tom, Tom2);
result(res3);
}
类模板基本语法&类模板与函数模板的区别
csharp
template<class nameT,class ageT>
class person1{
public:
nameT p1Name;
ageT p1Age;
person(nameT name,ageT age){
this->p1Name = name;
this->p1Age = age;
}
void showP1(){
cout<<"p1"<<endl;
}
};
int main(){
(x)person1 p1("Nick", 99);
person1<string, int> p1("Nick", 99);
}
类模板无法使用自动类型推导
类模板中成员函数的创建时机
类模板成员函数,在调用时才创建
csharp
class p1{
public:
void showp1(){
cout<<"p1"<<endl;
}
};
class p2{
public:
void showp2(){
cout<<"p2"<<endl;
}
};
template<class T>
class test{
public:
void p1show(){
T.showp1();
}
void p2show(){
T.showp2();
}
};
//在完成上面的代码后并不会报错,因为还无法确定T的具体类型
int main(){
test<p1> obj;
obj.p1show();
obj.p2show();
};
类模板对象做函数参数
1,指定传入类型法(√)
其他方法实际上都需要类模板结合函数模板使用
2,参数模板化法
3,类模板化法
csharp
template<class NameType, class AgeType = int>
class Person{
public:
Person(NameType name, AgeType age){
this->mName = name;
this->mAge = age;
}
void showPerson(){
cout<<"name: "<<this->mName<<"age: "<<this->age<<endl;
}
public:
NameType mName;
AgeType mAge;
};
//assign put in type for template
void printAssign(Person<string, int> &p){
p.showPerson();
}
void test01(){
Person<string, int>p{"Pa", 10};
printAssign(p);
}
//Parameter templating
template<class T1, class T2>
void printParatemplate(Person<T1, T2>&p){
p.showPerson();
cout<<"T1类型: "<<typeid(T1).name() <<endl;
cout<<"T2类型: "<<typeid(T2).name() <<endl;
}
void test02(){
Person <string, int>p("Pb", 20);
printParatemplate(p);
}
//entire class is templating
template<class T>
void printClasstemplate(T &p){
cout<<"T的类型: "<<typeid(T).name()<<endl;
p.showPerson();
}
void test03(){
Person<string, int>p("Pc", 30);
printClasstemplate(p);
}
int main(){
test01();
test02();
test03();
}
类模板与继承
子类继承父类模板,必须显式指定模板实际类型,如果想要保持灵活性,子类也必须为类模板。
arduino
template<class T>
class Base{
T m;
};
//class son : public Base语法报错,c++编译器需要给子类分配内存,没有明确的类型无法完成
class son : public Base<int>{
};
void test01(){
Son c;
}
//子类模板继承父类模板,可以用T2指定父类T的类型!
template<class T1, class T2>
class Son2 : public Base<T2>{
public:
Son2(){
cout<<typeid(T1).name()<<endl;
cout<<typeid(T1).name()<<endl;
}
};
test02(){
Son2<int, char> child;
}
类模板成员函数类外实现
类模板
kotlin
template<class T1, class T2>
class Person {
public:
T1 m_Name;
T2 m_Age;
Person(T1 name, T2 age);
void showPerson();
};
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 << "姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
}
类模板分文件编写
解决分文件编写时链接不到的问题。
person.h
ruby
template<class T1, class T2>
class Person{
T1 mName;
T2 mAge;
Person(T1 mName, T2 mAge);
show();
};
person.cpp
arduino
#include "person.h"
template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age){
this->mName = name;
this->mAge = age;
}
template<class T1, class T2>
void Person<T1, T2>::show(){
cout<<"..."<<endl;
}
main.cpp
c
(x)#include "person.h"
//error can't find corresponding func, generate in call
(√)#include "person.cpp"
//或者将.h .cpp 文件合并为.hpp文件,在main中包含
void test(){
Person<string, int>p("j", 18);
p.show();
}
类模板与友元
类模板友元函数的类内/外实现
arduino
template<class T1, class T2>class Person;
template<class T1, class T2>void showPerson2(Person<T1, T2>) {
cout << "out of class姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
}
template<class T1, class T2>class Person {
friend void showPerson(Person<T1, T2>& p) {
cout << "in class姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
}
friend void showPerson2<>(Person<T1, T2>& p);
public:
Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
项目:数组类封装
kotlin
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray {
private:
T* arrAd;
int arrCap;
int arrSiz;
public:
MyArray(int capa) {
this->arrCap = capa;
this->arrSiz = 0;
this->arrAd = new T[this->arrCap];
}
//copy
MyArray(const MyArray& arr) {
this->arrCap = arr.arrCap;
this->arrSiz = arr.arrSiz;
//this->arrAd = arr.arrAd;
this->arrAd = new T[arr.arrCap];
for (int i = 0; i < this->arrSiz; i++) {
this->arrAd[i] = arr.arrAd[i];
}
}
//operator=如果想要返回值作为左值使用,需要返回引用
MyArray& operator=(const MyArray& arr) {
if (this->arrAd != NULL) {
delete[] this->arrAd;
this->arrAd = NULL;
this->arrCap = 0;
this->arrSiz = 0;
}
this->arrCap = arr.arrCap;
this->arrSiz = arr.arrSiz;
this->arrAd = new T[arr.arrCap];
for (int i = 0; i < this->arrSiz; i++) {
this->arrAd[i] = arr.arrAd[i];
}
return *this;
}
void push_back(const T& val) {
if (this->arrCap == this->arrSiz) {
return;
}
this->arrAd[this->arrSiz] = val;
this->arrSiz++;
}
void pop_back() {
if (this->arrSiz == 0) {
return;
}
this->arrSiz--;
}
T& operator[](int index) {
return this->arrAd[index];
}
int getCap() {
return this->arrCap;
}
int getSiz() {
return this->arrSiz;
}
~MyArray() {
if (this->arrAd != NULL) {
delete[] this->arrAd;
}
}
};