前言
本文主要作為本人學習C\C++歷程的的一種記錄,以期望通過這種方式加深對知識點的記憶,查漏補缺,如有寫得不對的地方,歡迎大家批評改正,
模板概論
模板是泛型編程的基礎,是創建泛型類或函式的藍圖或公式,
C++提供了兩種模板機制:函式模板和類模板,函式模板,實際上是建立了一個通用函式,其函式型別和形參型別不具體制定,用一個虛擬的型別來代表,類模板和函式模板的定義和使用類似,
下面開始逐一介紹C++模板的應用,
函式模板
定義函式模板
點擊查看代碼
template<class T> //注意:T代表泛型的資料型別,不是只能寫T,
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
也可以這樣定義函式模板
點擊查看代碼
template<typename T>
void mySwap(T& a,T& b)
{
}
怎么使用函式模板?
點擊查看代碼
template<class T> //注意:T代表泛型的資料型別,不是只能寫T,
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
mySwap(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
//可以這樣定義函式模板
//template<typename T>
//void func(T a, T b)
//{
//
//}
template<class T>
T func1(T a, T b)
{
return a + b;
}
void test02()
{
int a = 10;
double b = 20.3;
//如果使用引數串列指定資料型別,那么實參中可以隱式轉換,
//如果轉換成功,就呼叫,轉換不成功就報錯
cout << func1<int>(a, b) << endl;
}
普通函式和函式模板的區別
點擊查看代碼
//1.普通函式可以進行隱式轉換,函式模版不能直接的進行隱性轉換
//普通函式
int myPlus(int a, int b)
{
cout << "普通函式" << endl;
return a + b;
}
//函式模板
template<class T>
int myPlus(T a, T b)
{
cout << "函式模板" << endl;
return a + b;
}
void test01()
{
int a = 10;
double b = 20;
myPlus(a, b); //普通函式可以進行隱性轉換
//myPlus2(a, b); //沒有與引數串列匹配的 函式模板 "myPlus2" 實體
myPlus<int>(a, b); //如果要進行隱性轉換,必須加上引數串列
}
普通函式和函式模板的呼叫規則
點擊查看代碼
//普通函式
int myPlus(int a, int b)
{
cout << "普通函式" << endl;
return a + b;
}
//函式模板
template<class T>
int myPlus(T a, T b)
{
cout << "函式模板" << endl;
return a + b;
}
//函式模板多載
template<class T>
void myPlus(T a, T b, T c)
{
cout << "函式模板myPlus(T a, T b, T c)" << endl;
}
//1、函式模板和普通函式都可以多載
void test02()
{
int a = 10;
int b = 20;
//2、如果普通函式和函式模板都可以實作的功能,普通函式優先呼叫
myPlus(a, b);
//3、可以使用<>空引數串列強制呼叫函式模板
myPlus<>(a, b);
//4、函式模板之間也可以進行多載
//5、如果函式模板可以產生更好的匹配,那么優先使用函式模板
char c1 = 'a';
char c2 = 'b';
myPlus(c1, c2);
}
模板機制剖析——c++編譯器是如何實作函式模板機制的?
- 編譯器并不是把函式模板處理成能夠處理任何型別的函式
- 函式模板通過具體型別產生不同的函式
- 編譯器會對函式模板進行兩次編譯,在宣告的地方對模板代碼本身進行編譯,在呼叫的地方對引數替換后的代碼進行編譯,
模板也具有局限性
點擊查看代碼
template<class T>
void mycompare(T a, T b)
{
if (a > b)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
void test01()
{
//如果傳入的是陣列名,那么函式模板中比較函式名的大小就沒有意義
int arr[20];
int arr2[10];
mycompare(arr, arr2);
}
為解決上述問題,提出了兩種方法
第一種:使用函式模板具體化
點擊查看代碼
class Maker
{
public:
Maker(string name, int age)
{
this->name = name;
this->age = age;
}
public:
string name;
int age;
};
template<class T>
void myfunc(T& a, T& b)
{
if (a > b)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
//具體化函式模板,注意上面的函式模板要有,才能具體化
template<>void myfunc<Maker>(Maker& a, Maker& b)
{
cout << "函式模板的具體化" << endl;
if (a.age > b.age)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
第二種:多載運算子
點擊查看代碼
class Maker1
{
public:
Maker1(string name, int age)
{
this->name = name;
this->age = age;
}
public:
string name;
int age;
};
bool operator>(Maker1& m1, Maker1& m2)
{
if (m1.name > m2.name && m1.age > m2.age)
{
return true;
}
else
{
return false;
}
}
void test()
{
Maker1 a("aaa", 18);
Maker1 b("bbb", 20);
if (a > b)
{
cout << "a>b" << endl;
}
else
{
cout << "a<=b" << endl;
}
}
定義類模板
點擊查看代碼
//類模板是把類中的資料型別引數化
template<class NameType,class AgeType>
class Maker
{
public:
Maker(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "Name:" << this->name << "Age:" << this->age << endl;
}
public:
NameType name;
AgeType age;
};
類模板的使用
點擊查看代碼
template<class NameType,class AgeType>
class Maker
{
public:
Maker(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "Name:" << this->name << "Age:" << this->age << endl;
}
public:
NameType name;
AgeType age;
};
//類模板的使用
void test()
{
//1.類模版不會自動推導資料型別,要顯示的告訴編譯器是什么型別
Maker<string, int> m("高啟強", 35);
m.printMaker();
//2.注意傳入的引數,傳入引數型別要程式員自己把握
Maker<int, int>m2(18, 20);
m2.printMaker();
//Maker<>m3("aaa", 18); //err:類模板“Maker"的引數太少,必須通過引數串列告訴編譯器是什么型別
}
類模板和函式模板的區別
- 類模板不會自動推導資料型別,要顯示的告訴編譯器是什么型別
- 函式模板可以根據實參來推導資料型別
類模板的默認型別及其使用
點擊查看代碼
template<class NameType, class AgeType=int>
class Maker2
{
public:
Maker2(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "Name:" << this->name << "Age:" << this->age << endl;
}
public:
NameType name;
AgeType age;
};
void test02()
{
//如果有默認型別,那么<>里可以少寫型別
Maker2<string> m("高啟強", 35);
//Maker2<string, int> m("高啟蘭", 20);
m.printMaker();
//以傳入的型別為準
Maker2<string, double> m2("高啟盛", 24.22);
m2.printMaker();
}
//5、類模板的默認引數注意
//默認型別后面的泛型型別都必須有默認型別
template<class NameType, class AgeType = int, class T = int>
class Maker3
{
public:
Maker3(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "Name:" << this->name << " Age:" << this->age << endl;
}
public:
NameType name;
AgeType age;
};
void test03()
{
Maker3<string> m("高啟強", 35);
m.printMaker();
}
類模板做函式引數
點擊查看代碼
template<class NameType, class AgeType>
class Maker
{
public:
Maker(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "name = " << this->name << " " << " age = " << this->age << endl;
}
public:
NameType name;
AgeType age;
};
//類模板做函式引數
//1.指定傳入的資料型別
void func(Maker<string, int>& m)
{
m.printMaker();
}
//2.引數模版化(常用)
template<class T1, class T2>
void func2(Maker<T1, T2>& m)
{
m.printMaker();
}
//3.整個類 模版化
template<class T>
void func3(T& m)
{
m.printMaker();
}
類模板的繼承
點擊查看代碼
//1、普通類繼承類模板
template<class T>
class Father
{
public:
Father()
{
m = 20;
}
public:
T m;
};
//普通類 繼承 類模板
class Son : public Father<int> //2、要告訴編譯器父類的泛型資料型別具體是什么型別
{
public:
};
//2、類模板 繼承 類模板
//類模板 繼承 類模板
template<class T1,class T2>
class Son2 :public Father<T2> //要告訴編譯器父類的泛型資料型別具體是什么型別
{
};
類模板的成員函式的類內實作
點擊查看代碼
template<class NameType,class AgeType>
class Maker
{
public:
Maker(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
void printMaker()
{
cout << "Name:" << this->name << " " << "Age:" << this->age << endl;
}
public:
NameType name;
AgeType age;
};
類模板的成員函式類外實作
點擊查看代碼
template<class NameType,class AgeType>
class Maker
{
public:
Maker(NameType name, AgeType age);
void printMaker();
public:
NameType name;
AgeType age;
};
//類模板的成員函式類外實作
//成員函式必須寫成函式模板,并且寫上引數串列
template<class NameType,class AgeType>
Maker<NameType,AgeType>::Maker(NameType name, AgeType age)
{
cout << "建構式" << endl;
this->name = name;
this->age = age;
}
template<class NameType,class AgeType>
void Maker<NameType, AgeType>::printMaker()
{
cout << "Name:" << this->name << " " << "Age:" << this->age << endl;
}
類模板的友元實作
類內實作
點擊查看代碼
template<class NameType,class AgeType>
class Maker
{
friend void printMaker(Maker<NameType, AgeType>& p)
{
cout << "類內實作" <<" "<< p.name << " " << p.age << endl;
}
public:
Maker(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
private:
NameType name;
AgeType age;
};
類外實作
點擊查看代碼
//1、宣告模板
template<class NameType,class AgeType>
class Maker2;
//2、宣告函式模板
//告訴編譯器下面有printMaker2的實作
template<class NameType,class AgeType>
void printMaker2(Maker2<NameType, AgeType>& p);
template<class NameType, class AgeType>
class Maker2
{
//3、在函式名和()之間加上<>
friend void printMaker2<>(Maker2<NameType, AgeType>& p);
//編譯器不知道printMaker2下面有沒有實作,需要知道函式的結構
public:
Maker2(NameType name, AgeType age)
{
this->name = name;
this->age = age;
}
private:
NameType name;
AgeType age;
};
//友元在類外實作要寫成函式模板
template<class NameType,class AgeType>
void printMaker2(Maker2<NameType, AgeType>& p)
{
cout << "類外實作的友元函式" << " "<<p.name << " " << p.age << endl;
}
類模板實作陣列
MyArray.hpp
點擊查看代碼
#pragma once
template<class T>
class MyArray
{
public:
MyArray(int capacity)
{
this->mCapacity = capacity;
this->mSize = 0;
//T如果是Maker,這里要呼叫什么建構式,要呼叫無參構造
p = new T[this->mCapacity];
}
//拷貝構造
MyArray(const MyArray &arr)
{
this->mCapacity = arr.mCapacity;
this->mSize = arr.mSize;
p = new T[arr.mCapacity];
for (int i = 0; i < this->mSize; i++)
{
p[i] = arr.p[i];
}
}
//賦值函式
MyArray& operator=(const MyArray& arr)
{
if (this->p != NULL)
{
delete[] this->p;
this->p = NULL;
}
p = new T[arr.mCapacity];
this->mSize = arr.mSize;
this->mCapacity = arr.mCapacity;
for (int i = 0; i < this->mSize; i++)
{
p[i] = arr.p[i];
}
return *this;
}
//多載[]
T& operator[](int index)
{
return this->p[index];
}
//尾插
void Push_Back(const T& val)
{
if (this->mSize == this->mCapacity)
{
return;
}
this->p[this->mSize] = val;
this->mSize++;
}
//尾刪
void Pop_Back()
{
if (this->mSize == 0)
{
return;
}
this->mSize--;
}
//析構
~MyArray()
{
if (this->p != NULL)
{
delete[] p;
p = NULL;
}
cout << "解構式" << endl;
}
int getSize()
{
return this->mSize;
}
private:
T* p;
int mCapacity;
int mSize;
};
點擊查看代碼
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<iostream>
using namespace std;
#include"MyArray.hpp"
class Maker
{
public:
Maker()
{
cout << "無參構造" << endl;
}
Maker(string name,int age)
{
this->name = name;
this->age = age;
}
public:
string name;
int age;
};
void printMaker(MyArray<Maker>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名:" << arr[i].name << " 年齡:" << arr[i].age << endl;
}
}
void test()
{
//Maker型別
MyArray<Maker>myarr(4);
Maker m1("小明", 18);
Maker m2("小強", 19);
Maker m3("小棟", 20);
Maker m4("小興", 21);
myarr.Push_Back(m1);
myarr.Push_Back(m2);
myarr.Push_Back(m3);
myarr.Push_Back(m4);
printMaker(myarr);
//int型別
MyArray<int>myint(10);
for (int i = 0; i < 10; i++)
{
myint.Push_Back(i + 1);
}
for (int i = 0; i < 10; i++)
{
cout << myint[i] << " " << endl;
}
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
總結
模板是一個比較重要的概念,是創建泛型類或函式的藍圖或公式,庫容器,比如迭代器和演算法,都是泛型編程的例子,它們都使用了模板的概念,
-學習C++任重而道遠,本人愚鈍,唯有勤加練習方能查漏補缺,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/544313.html
標籤:C++
上一篇:排列組合
