C++的一種編程思想稱為泛型編程,用到的技術就是模板
C++提供兩種模板:函數模板和類模板。
1.函數模板
1.函數模板作用
建立一個通用函數,其返回值類型和形參類型可以用一個虛擬的類型來代替,提高代碼復用性,將類型參數化。
2.語法
template<typename T>
//函數聲明或定義
template--聲明創建模板
typename--表明其后面的符號是一種數據類型,可以用class代替
T--通用的數據類型,名稱可以替換,通常為大寫字母
3.例子
未應用模板(代碼復雜,通用性差)
void intswap(int& a, int& b)
{int c;c = a;a = b;b = c;
}
void doubleswap(double& a, double& b)
{double c;c = a;a = b;b = c;
}
應用模板(代碼簡潔,通用性強)
注意:函數模板一次只能對應一個函數,也就是說T不能多次重復使用
template<typename T>
void swap(T& a, T& b)
{T c;c = a;a = b;b = c;
}
4.模板使用方式
1.自動類型推導
swap(a,b);
2.顯示指定類型
swap<int>(a,b);
5.注意事項
1.自動類型推導
必須推導出一只的數據類型T才可以使用
反例:
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void swap(T& a, T& b)
{T c;c = a;a = b;b = c;
}
int main()
{int a=0;char b = '12';swap(a, b);return 0;
}
2.T的類型必須確定
模板必須要確定T的類型,才可以使用
反例:
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void swap()
{cout << "swap" << endl;
}
int main()
{swap();return 0;
}
6.案例
1.題目
對數組進行降序排序
2.代碼
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void sort(T a[],int len)
{T temp;int max ;for (int i = 0; i < len; i++){max = i;for (int j = i; j < len; j++){if (a[j] > a[max]){temp = a[j];a[j] = a[max];a[max] = temp;}}}
}
int main()
{char c[6] = "badce";sort(c,5);cout << c << endl;int a[6] = {4,5,2,3,1};sort(a, 5);for(int i=0;i<5;i++)cout << a[i] << endl;return 0;
}
3.結果
7.普通模板與函數模板區別
·普通函數可以發生自動類型轉換(隱式類型轉換)
·函數模板調用時,如果利用自動類型推導,則不會發生隱式類型轉換
·如果利用顯示指定類型的方式,可以發生隱式類型轉換
1.普通函數隱式類型轉換
#include<iostream>
using namespace std;
#include<string>
int fun(int a, int b)
{return a + b;
}
int main()
{int a = 10;char c = 'c';//a=97,c=99cout << fun(a, c) << endl;return 0;
}
2.自動類型推導不可以使用
#include<iostream>
using namespace std;
#include<string>
template<typename T>
int fun(T a, T b)
{return a + b;
}
int main()
{int a = 10;char c = 'c';cout << fun(a, c) << endl;return 0;
}
3.顯式指定類型可以使用
#include<iostream>
using namespace std;
#include<string>
template<typename T>
int fun(T a, T b)
{return a + b;
}
int main()
{int a = 10;char c = 'c';cout << fun<int>(a, c) << endl;return 0;
}
4.建議
建議使用顯式指定類型的方式調用,這種更加明確。
8.普通函數與函數模板調用規則
1.函數模板可以發生重載
1.普通函數與函數模板重載
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{cout << "函數模板" << endl;
}
void fun()
{cout << "普通函數" << endl;
}
int main()
{fun(1);fun();return 0;
}
2.函數模板之間的重載
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{cout << "函數模板" << endl;
}
template<typename T>
void fun(T a,T b)
{cout << "重載函數模板" << endl;
}
int main()
{fun(1);fun(1, 1);return 0;
}
2.調用優先級
如果普通函數和函數模板都可以調用,優先調用函數模板
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{cout << "函數模板" << endl;
}
void fun( int a)
{cout << "普通函數" << endl;
}
int main()
{fun(1);return 0;
}
注意:就算普通函數只有一個聲明也不會調用函數模板(會報錯)。
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{cout << "函數模板" << endl;
}
void fun(int a);
int main()
{fun(1);return 0;
}
3.強制調用模板函數
通過空模板參數列表,強制調用函數模板
fun<>(1);
4.發生隱式類型轉換時的優先級
當普通函數發生隱式類型轉換時,會優先調用函數模板(程序會使用最優選擇)
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{cout << "函數模板" << endl;
}
void fun(char a)
{cout << "普通函數調用" << endl;
}
int main()
{fun(1);return 0;
}
2.類模板
1.定義
建立一個通用類,類中的成員數據類型可以不具體指定,用一個虛擬的類型來代替。
2.語法
template<typename T>
//類
template--聲明創建模板
typename--表明其后面的符號是一種數據類型,可以用class代替
T--通用的數據類型,名稱可以替換,通常為大寫字母
3.例子
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:person(A name, B age){this->name = name;this->age = age;}void show(){cout << this->name << this->age << endl;}A name;B age;
};
int main()
{person<string, int>p1("孫悟空", 999);p1.show();return 0;
}
4.類模板與函數模板區別
1.類模板不可以使用自動類型推導,只能自己設置類型。
2.類模板的模板參數列表中可以默認參數
模板參數表:即為尖括號里面的
template<class A,class B>
默認參數
template<class A,class B=int>
5.類模板中的成員函數創建時機
只要不去調用,就不會創建,所以a.fun()不會報錯
#include<iostream>
using namespace std;
#include<string>
template<class A>
class person
{
public:A a;void fun(){a.fun1();}
};
int main()
{return 0;
}
6.類模板對象做函數參數
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:A name;B age;person(A name, B age){this->name = name;this->age=age;}void show(){cout << this->name << endl;cout << this->age << endl;}
};
void fun(person<string, int>&p1)
{p1.show();
}
int main()
{person<string, int>p1("孫悟空", 100);fun(p1);return 0;
}
此時的函數參數應該是“person<string, int>&p1”
7.函數模板參數模板化
使用函數模板來提高復用性
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:A name;B age;person(A name, B age){this->name = name;this->age=age;}void show(){cout << this->name << endl;cout << this->age << endl;}
};
template<class T1,class T2>
void fun(person<T1, T2>&p1)
{p1.show();
}
int main()
{person<string, int>p1("孫悟空", 100);fun(p1);return 0;
}
1.類型顯示方法
如果想顯示出自動類型轉換的類型是什么,可以用這個方法
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:A name;B age;person(A name, B age){this->name = name;this->age=age;}void show(){cout <<"姓名:" << this->name << endl;cout << "年齡:" << this->age << endl;}
};
template<class T1,class T2>
void fun(person<T1, T2>&p1)
{p1.show();cout <<"T1的類型:" << typeid(T1).name() << endl;cout <<"T2的類型:" << typeid(T2).name() << endl;
}
int main()
{person<string, int>p1("孫悟空", 100);fun(p1);return 0;
}
8.將做參數的整個類都模板化
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:A name;B age;person(A name, B age){this->name = name;this->age=age;}void show(){cout <<"姓名:" << this->name << endl;cout << "年齡:" << this->age << endl;}
};
template<class T>
void fun(T &p1)
{p1.show();cout << "T的數據類型:" << typeid(T).name() << endl;
}
int main()
{person<string, int>p1("孫悟空", 100);fun(p1);return 0;
}
9.類模板與繼承
父類如果是一個模板,子類在繼承時需要指出他的數據類型
1.手動指定數據類型
#include<iostream>
using namespace std;
#include<string>
template<class T>
class base
{
public:T a;
};
class son :public base<int>
{};
int main()
{return 0;
}
2.將子類也變為模板
#include<iostream>
using namespace std;
#include<string>
template<class T>
class base
{
public:T a;
};
template<class T1,class T2>
class son :public base<T2>
{
public:T1 a;
};
int main()
{son<string, int>p1;return 0;
}
10.類模板的函數類外實現
1.構造函數的類外實現
#include<iostream>
using namespace std;
#include<string>
template<class T1,class T2>
class person
{
public:T1 name;T2 age;person(T1 name, T2 age);
};
template<class T1,class T2>
person<T1,T2>::person(T1 name,T2 age)
{this->name = name;this->age = age;
}
int main()
{return 0;
}
2.成員函數的類外實現
#include<iostream>
using namespace std;
#include<string>
template<class T1,class T2>
class person
{
public:T1 name;T2 age;person(T1 name,T2 age);void fun();
};
template<class T1, class T2>
person<T1, T2>::person(T1 name, T2 age)
{this->name = name;this->age = age;
}
template<class T1,class T2>
void person<T1, T2>::fun()
{cout << name << endl;cout << age << endl;
}
int main()
{person<string, int>p("埃里給", 18);p.fun();return 0;
}
11.類模板分文件編寫
該程序包含一個頭文件和一個源文件,頭文件負責函數實現,源文件負責函數調用
.hpp后綴名:約定俗成的包含類模板的聲明與實現。
1.頭文件(person.hpp)
#pragma once
#include<iostream>
using namespace std;
#include<string>
template<class T1, class T2>
class person
{
public:person(T1 name, T2 age);void show();T1 name;T2 age;
};
template<class T1, class T2>
person<T1, T2>::person(T1 name, T2 age)
{this->name = name;this->age = age;
}
template<class T1, class T2>
void person<T1, T2>::show()
{cout << name << endl;cout << age << endl;
}
2.源文件
#include"person.hpp"
int main()
{person<string,int>p("埃里給", 18);p.show();return 0;
}
3.輸出結果
12.類模板與友元
不想寫了,想寫的時候補上