1 模板編程的基本概念
C++ 的模板編程是一種編程技術(shù),它允許程序員編寫處理不同類型數(shù)據(jù)的通用代碼。通過使用模板,可以創(chuàng)建與特定數(shù)據(jù)類型無(wú)關(guān)的函數(shù)或類,這些函數(shù)或類在編譯時(shí)可以根據(jù)需要生成特定數(shù)據(jù)類型的版本。這增加了代碼的復(fù)用性、靈活性和類型安全性。
1.1 模板編程的本質(zhì)
從本質(zhì)上來說, C++ 的模板編程是一種編譯時(shí)多態(tài)性( compile-time polymorphism )的機(jī)制。在 C++ 中,多態(tài)性通常指的是以統(tǒng)一的方式處理不同類型的數(shù)據(jù)或?qū)ο蟮哪芰?。運(yùn)行時(shí)多態(tài)性( runtime polymorphism )通常通過虛函數(shù)實(shí)現(xiàn),它允許在運(yùn)行時(shí)根據(jù)對(duì)象的實(shí)際類型來調(diào)用不同的函數(shù)。而編譯時(shí)多態(tài)性則通過模板實(shí)現(xiàn),它允許在編譯時(shí)根據(jù)所使用的數(shù)據(jù)類型來生成不同的代碼。
模板編程的本質(zhì)可以歸結(jié)為以下幾點(diǎn):
類型參數(shù)化
模板允許程序員定義接受類型作為參數(shù)的函數(shù)或類。這些類型參數(shù)在模板實(shí)例化時(shí)被具體的數(shù)據(jù)類型所替換,從而生成特定類型的代碼。這種類型參數(shù)化使得代碼能夠以一種類型無(wú)關(guān)的方式編寫,提高了代碼的復(fù)用性和靈活性。
編譯時(shí)生成
模板實(shí)例化發(fā)生在編譯時(shí),編譯器根據(jù)提供的類型參數(shù)生成特定類型的函數(shù)或類的代碼。這意味著在編譯時(shí)就確定了函數(shù)或類的具體實(shí)現(xiàn),而不是在運(yùn)行時(shí)。這種編譯時(shí)生成的方式使得模板編程具有很高的性能優(yōu)勢(shì)。
類型安全
由于模板實(shí)例化是在編譯時(shí)進(jìn)行的,編譯器能夠?qū)︻愋瓦M(jìn)行嚴(yán)格的檢查,確保類型安全。這意味著在編譯時(shí)就能夠發(fā)現(xiàn)類型錯(cuò)誤,而不是等到運(yùn)行時(shí)才出現(xiàn)錯(cuò)誤。
泛型編程
模板編程是一種泛型編程的形式,它允許程序員編寫與具體數(shù)據(jù)類型無(wú)關(guān)的通用代碼。這種泛型編程的能力使得代碼更加簡(jiǎn)潔、易讀和可維護(hù)。
元編程能力
模板編程還具有元編程的能力,即利用模板在編譯時(shí)進(jìn)行編程。這包括模板特化、模板偏特化、遞歸模板等技術(shù),它們?cè)试S程序員在編譯時(shí)進(jìn)行復(fù)雜的邏輯判斷和代碼生成。
綜上所述, C++ 的模板編程的本質(zhì)是一種編譯時(shí)多態(tài)性的機(jī)制,它允許程序員以類型無(wú)關(guān)的方式編寫通用代碼,并在編譯時(shí)生成特定類型的代碼。這種機(jī)制提高了代碼的復(fù)用性、靈活性和性能,同時(shí)保證了類型安全。通過模板編程,程序員能夠編寫出更加優(yōu)雅、高效和可維護(hù)的代碼。
1.2 模板編程的應(yīng)用場(chǎng)景
C++ 模板編程支持使用通用代碼處理多種數(shù)據(jù)類型。這種編程模式在多個(gè)應(yīng)用場(chǎng)景中都非常有用,以下是 C++ 模板編程的一些典型應(yīng)用場(chǎng)景:
數(shù)據(jù)類型與算法相分離的泛型編程
這是模板編程最常見的應(yīng)用之一。通過將數(shù)據(jù)類型與算法分離,我們可以實(shí)現(xiàn)泛型編程,使代碼能夠處理多種數(shù)據(jù)類型而無(wú)需重復(fù)編寫。例如,在STL(標(biāo)準(zhǔn)模板庫(kù))中,容器(如std::vector
、std::list
)和算法(如std::sort
、std::find
)都是通過模板實(shí)現(xiàn)的,這使得它們可以與任何數(shù)據(jù)類型一起使用,從而大大提高了代碼的重用性。
類型適配( Traits )
類型適配是模板編程中的另一個(gè)重要概念。通過使用特性( Traits )模板,我們可以根據(jù)數(shù)據(jù)類型提供特定的類型信息或行為。這在需要根據(jù)數(shù)據(jù)類型執(zhí)行不同操作時(shí)非常有用。例如,根據(jù)數(shù)據(jù)類型是否為指針或引用,可以提供不同的類型適配實(shí)現(xiàn)。
函數(shù)轉(zhuǎn)發(fā)
函數(shù)轉(zhuǎn)發(fā)是 C++11 引入的一種新特性,它允許我們編寫能夠轉(zhuǎn)發(fā)其參數(shù)給另一個(gè)函數(shù)的模板函數(shù)。這在創(chuàng)建通用函數(shù)包裝器或代理時(shí)非常有用。通過使用函數(shù)轉(zhuǎn)發(fā),我們可以編寫一個(gè)模板函數(shù),該函數(shù)能夠?qū)⑵鋮?shù)以正確的方式轉(zhuǎn)發(fā)給另一個(gè)函數(shù),而無(wú)需知道目標(biāo)函數(shù)的具體簽名。
元編程
模板元編程是 C++ 模板編程的高級(jí)應(yīng)用之一。它允許我們?cè)诰幾g時(shí)執(zhí)行一系列的邏輯判斷和計(jì)算。元編程通常用于常量計(jì)算、類型操作和策略模式等場(chǎng)景。例如,可以使用遞歸模板來實(shí)現(xiàn)編譯時(shí)的階乘計(jì)算,或者使用模板特化來實(shí)現(xiàn)不同類型的特定行為。
編譯時(shí)容器與算法
通過模板元編程,我們還可以實(shí)現(xiàn)編譯時(shí)的容器和算法。這意味著在編譯階段就可以生成針對(duì)特定數(shù)據(jù)類型的容器和算法實(shí)現(xiàn),從而在運(yùn)行時(shí)獲得更高的性能。例如,我們可以使用模板元編程實(shí)現(xiàn)編譯時(shí)的靜態(tài)數(shù)組和排序算法。
策略模式
策略模式是一種設(shè)計(jì)模式,它允許程序在運(yùn)行時(shí)根據(jù)需要選擇不同的算法實(shí)現(xiàn)。通過模板編程,可以實(shí)現(xiàn)類似的功能,但在編譯時(shí)進(jìn)行選擇。這有助于提高代碼的靈活性和可擴(kuò)展性。
跨平臺(tái)編程
在跨平臺(tái)編程中,由于不同平臺(tái)可能使用不同的數(shù)據(jù)類型和大小,使用模板可以確保代碼在不同平臺(tái)上的兼容性和可移植性。通過編寫與平臺(tái)無(wú)關(guān)的模板代碼,我們可以更容易地在多個(gè)平臺(tái)上編譯和運(yùn)行程序。
綜上所述, C++ 模板編程在多個(gè)應(yīng)用場(chǎng)景中都發(fā)揮著重要作用,包括數(shù)據(jù)類型與算法相分離的泛型編程、類型適配、函數(shù)轉(zhuǎn)發(fā)、元編程、編譯時(shí)容器與算法、策略模式以及跨平臺(tái)編程等。這些應(yīng)用場(chǎng)景共同展示了模板編程在提高代碼重用性、類型安全性、性能和靈活性方面的優(yōu)勢(shì)。
2 函數(shù)模板
函數(shù)模板是一種特殊的函數(shù)定義,它使用模板參數(shù)來指定函數(shù)可以處理的數(shù)據(jù)類型。模板參數(shù)在函數(shù)定義中以類型參數(shù)的形式出現(xiàn),它們可以是任何有效的 C++ 數(shù)據(jù)類型,包括內(nèi)置類型和用戶定義的類型。
2.1 函數(shù)模板的定義和實(shí)例化
函數(shù)模板的定義包含了一個(gè)或多個(gè)類型參數(shù),這些類型參數(shù)在函數(shù)定義中以 typename 或 class 關(guān)鍵字進(jìn)行聲明。這些類型參數(shù)在函數(shù)體內(nèi)部被當(dāng)作普通的數(shù)據(jù)類型來使用。
函數(shù)模板的定義
函數(shù)模板的一般定義形式如下:
template <typename T1, typename T2, ..., typename Tn>
return_type functionName(parameterList)
{
// 函數(shù)體
}
其中 T1, T2, …, Tn 是類型參數(shù),代表可以是任何數(shù)據(jù)類型的占位符。return_type 是函數(shù)的返回類型, functionName 是函數(shù)的名稱, parameterList 是函數(shù)的參數(shù)列表。
如下是一個(gè)簡(jiǎn)單的函數(shù)模板示例,該模板定義了一個(gè)加法函數(shù):
template <typename T>
T add(const T& a, const T& b)
{
return a+b;
}
在上面代碼中, T 是一個(gè)類型參數(shù),它可以是任何數(shù)據(jù)類型。 add 函數(shù)接受兩個(gè)類型為 T 的引用參數(shù),并返回它們相加的值。
函數(shù)模板的實(shí)例化
當(dāng)函數(shù)模板被調(diào)用時(shí),編譯器會(huì)根據(jù)提供的實(shí)際參數(shù)類型來推斷類型參數(shù)的具體類型,并生成一個(gè)具體的函數(shù)實(shí)例,這個(gè)過程稱為函數(shù)模板的實(shí)例化。
例如,如果使用 int 類型來調(diào)用上面的 add 函數(shù)模板:
int a = 1;
int b = 2;
int sum = add(a, b); // 這里會(huì)實(shí)例化一個(gè) int 類型的 add 函數(shù)
編譯器會(huì)生成一個(gè)專門處理 int 類型的 add 函數(shù)實(shí)例:
int add(const int& a, const int& b)
{
return a+b;
}
同樣地,如果使用 double 類型來調(diào)用 add 函數(shù)模板,編譯器會(huì)生成一個(gè)處理 double 類型的函數(shù)實(shí)例。
顯式實(shí)例化
除了隱式地通過函數(shù)調(diào)用進(jìn)行實(shí)例化外,我們還可以顯式地要求編譯器為特定的類型生成函數(shù)模板的實(shí)例。這通常在編譯時(shí)性能優(yōu)化或者某些特殊場(chǎng)景下是有用的。
顯式實(shí)例化的語(yǔ)法如下:
template void functionName<T>(parameterList);
對(duì)于上面的 add 函數(shù)模板,如果想要顯式地實(shí)例化一個(gè)處理 int 類型的版本,可以這樣做:
template int add<int>(const int&, const int&);
顯式實(shí)例化通常是在頭文件中完成的,以確保在多個(gè)源文件中使用時(shí)鏈接器可以找到正確的實(shí)例。
2.2 函數(shù)模板的自動(dòng)類型推導(dǎo)
函數(shù)模板的自動(dòng)類型推導(dǎo)是一種編譯器特性,它允許在調(diào)用函數(shù)模板時(shí)自動(dòng)確定模板參數(shù)的類型。這種自動(dòng)類型推導(dǎo)機(jī)制極大地簡(jiǎn)化了代碼,并提高了代碼的可讀性和可維護(hù)性。
在調(diào)用一個(gè)函數(shù)模板時(shí),編譯器會(huì)根據(jù)傳遞給函數(shù)的實(shí)際參數(shù)來推導(dǎo)模板參數(shù)的類型。這個(gè)過程通常被稱為模板參數(shù)的類型推導(dǎo)或類型推斷。
2.2.1 自動(dòng)類型推導(dǎo)的基本使用
如下為樣例代碼:
#include <iostream>
template <typename T>
T add(const T& a, const T& b)
{
return a + b;
}
int main()
{
int sum1 = add(1, 2);
double sum2 = add(1.1, 2.1);
return 0;
}
在上面代碼中,add 是一個(gè)函數(shù)模板,它接受兩個(gè)類型為 T 的參數(shù),并返回它們的和。類型 T 是一個(gè)模板參數(shù),代表可以是任何數(shù)據(jù)類型的占位符。
當(dāng)調(diào)用這個(gè)函數(shù)模板時(shí),編譯器會(huì)自動(dòng)推導(dǎo)類型 T 。在第一個(gè)調(diào)用 add(1, 2) 中,編譯器能夠推導(dǎo)出 T 的類型為 int,因?yàn)閮蓚€(gè)參數(shù)都是整數(shù)。類似地,在第二個(gè)調(diào)用 add(1.1, 2.1) 中,編譯器推導(dǎo)出 T 的類型為 double ,因?yàn)閮蓚€(gè)參數(shù)都是浮點(diǎn)數(shù)。類型推導(dǎo)的規(guī)則通常是針對(duì)直觀的數(shù)據(jù)類型,但是當(dāng)涉及到引用、指針、模板中包含多個(gè)類型時(shí),上面代碼中的簡(jiǎn)單自動(dòng)類型推導(dǎo)有可能會(huì)無(wú)法滿足。此時(shí)就需要使用 C++11 的新特性來處理。
2.2.2 使用 decltype 與 auto
C++11 及其之后的版本引入了更強(qiáng)大的類型推導(dǎo)機(jī)制,即 decltype 和 auto 的聯(lián)合使用,可以進(jìn)一步簡(jiǎn)化代碼并提高類型推導(dǎo)的靈活性。
如下為樣例代碼:
#include <iostream>
template <class A, class B>
auto add(A a, B b) -> decltype(a + b)
{
return a + b;
}
int main()
{
auto sum1 = add(1, 2);
auto sum2 = add(1.1, 2.1);
return 0;
}
在上面中,decltype(a + b) 允許編譯器推導(dǎo)返回值的類型,而不僅僅是函數(shù)參數(shù)的類型。在這個(gè)場(chǎng)景下,sum1 與 sum2 的類型分別被推導(dǎo)為 int 與 double 。
C++14 支持的語(yǔ)法 decltype(auto) 更為簡(jiǎn)潔,可以將上面代碼中的函數(shù)模板修改為:
template <class A, class B>
decltype(auto) add(A a, B b)
{
return a + b;
}
使用 decltype 與 auto 尤其對(duì)模板函數(shù)中引用與 const 限定符的處理更為有效,如下為樣例代碼:
#include <iostream>
template <typename T>
void func(T&& t)
{
decltype(t) val = t; // a 的類型與 t 相同,包括引用和 const 限定符
// ...
}
int main()
{
int a = 1;
const int& b = a;
func(a); // t 的類型為 int& , val 的類型也為 int&
func(b); // t 的類型為 const int& , val 的類型也為 const int&
return 0;
}
在這個(gè)例子中,函數(shù)模板 func 接受一個(gè)右值引用參數(shù) t ,并使用 decltype(t) 來聲明一個(gè)局部變量 val ,其類型與 t 完全相同,包括引用和 const 限定符。這允許函數(shù)模板在處理不同類型的參數(shù)時(shí)保持更高的靈活性。
2.3 函數(shù)模板的顯式類型指定
函數(shù)模板的顯式類型指定是指在調(diào)用函數(shù)模板時(shí)明確指定模板參數(shù)的類型。這通常在希望消除類型推導(dǎo)的歧義或明確指定一個(gè)類型而不是讓編譯器自動(dòng)推導(dǎo)時(shí)非常有用。
使用顯式類型指定的語(yǔ)法是在函數(shù)名后面的尖括號(hào) < > 中直接列出模板參數(shù)類型。這允許你在調(diào)用模板函數(shù)時(shí)提供具體的類型,即使這些類型可以從傳遞給函數(shù)的參數(shù)中推導(dǎo)出來。
如下為樣例代碼:
#include <iostream>
#include <typeinfo>
template <typename T1, typename T2>
decltype(auto) add(T1 t1, T2 t2)
{
return t1 + t2;
}
int main()
{
auto sum1 = add(1, 2);
printf("type of sum1 is %s\n", typeid(sum1).name());
auto sum2 = add<double, double>(1, 2);
printf("type of sum2 is %s\n", typeid(sum2).name());
return 0;
}
上面代碼的輸出為:
type of sum1 is int
type of sum2 is double
在這個(gè)例子中,add 是一個(gè)函數(shù)模板,它接受類型為 T1 、 T2 的參數(shù)。在 main 函數(shù)中,首先以正常方式調(diào)用 add 函數(shù),讓編譯器從傳遞給函數(shù)的參數(shù)中推導(dǎo)出 T 的類型,最后的返回類型為 int 。然后,顯式地指定了 T 的類型,最后的返回類型為 double 。
2.4 函數(shù)模板的特化
函數(shù)模板的特化(Function Template Specialization)是C++模板編程中的一個(gè)重要概念,它支持為特定的類型或一組類型提供定制的模板實(shí)現(xiàn)。特化版本的函數(shù)模板會(huì)覆蓋通用模板的版本,當(dāng)使用特化類型調(diào)用函數(shù)模板時(shí),將使用特化版本的實(shí)現(xiàn)。
函數(shù)模板的特化通常指的是完全特化(類模板同時(shí)支持完全特化與部分特化),但是可以通過為特定的類型組合創(chuàng)建新的函數(shù)模板或重載現(xiàn)有的函數(shù)來實(shí)現(xiàn)部分特化的效果。
完全特化是指為函數(shù)模板提供一個(gè)完全限定的類型實(shí)現(xiàn)。這意味著為特定的類型提供了一個(gè)獨(dú)立的實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)將僅適用于該類型。完全特化的語(yǔ)法與通用模板的語(yǔ)法類似,但在模板參數(shù)列表中使用具體的類型替代類型參數(shù)。
如下為樣例代碼:
#include <iostream>
// 通用模板
template <typename T1, typename T2>
decltype(auto) add(T1 t1, T2 t2)
{
printf("call general template\n");
return t1 + t2;
}
// 特化模板,僅適用于 int , int 類型
template <>
decltype(auto) add<int>(int t1, int t2)
{
printf("call specialized template for int , int\n");
return t1 + t2;
}
int main()
{
// 調(diào)用特化模板
auto sum1 = add(1, 2);
// 調(diào)用通用模板
auto sum2 = add(1.2, 2.3);
return 0;
}
上面代碼的輸出為:
call specialized template for int , int
call general template
在這個(gè)例子中,當(dāng) add 函數(shù)以 int 類型調(diào)用時(shí),將使用完全特化版本的實(shí)現(xiàn)。對(duì)于其他類型,如 double 或 std::string ,將使用通用模板的實(shí)現(xiàn)。
由于函數(shù)模板不支持部分特化,如果需要為一組類型提供特定的實(shí)現(xiàn),通常需要通過重載函數(shù)來實(shí)現(xiàn)類似的效果。這些函數(shù)具有與通用模板相同的名稱,但參數(shù)類型不同。
如下為樣例代碼:
#include <iostream>
// 通用模板
template <typename T1, typename T2>
decltype(auto) add(T1 t1, T2 t2)
{
printf("call general template\n");
return t1 + t2;
}
// 重載函數(shù),僅適用于 int ,int 類型
decltype(auto) add(int t1, int t2)
{
printf("call overloaded function for int , int\n");
return t1 + t2;
}
// 重載函數(shù),僅適用于 double ,int 類型
decltype(auto) add(double t1, int t2)
{
printf("call overloaded function for double , int\n");
return t1 + t2;
}
int main()
{
// 調(diào)用重載函數(shù):int ,int
auto sum1 = add(1, 2);
// 調(diào)用重載函數(shù):double ,int
auto sum2 = add(1.2, 2);
// 調(diào)用通用模板
auto sum3 = add(1.2, 2.3);
return 0;
}
上面代碼的輸出為:
call overloaded function for int , int
call overloaded function for double , int
call general template
3 類模板
類模板允許定義可以在實(shí)例化時(shí)進(jìn)行指定數(shù)據(jù)類型的類。換句話說,類模板是一個(gè)參數(shù)化類型,它使用一個(gè)或多個(gè)參數(shù)來創(chuàng)建一系列類。
類模板的主要優(yōu)勢(shì)在于,它可以減少代碼重復(fù),提高編程效率。通過為一系列僅成員數(shù)據(jù)類型不同的類創(chuàng)建一個(gè)類模板,程序員只需提供一套程序代碼,就可以生成多種具體的類,這些類可以看作是類模板的實(shí)例。
3.1 類模板的定義和實(shí)例化
類模板的定義類似于函數(shù)模板的定義。在類模板中,可以指定一個(gè)或多個(gè)類型參數(shù),這些類型參數(shù)在實(shí)例化時(shí)將被實(shí)際的數(shù)據(jù)類型替代。
類模板的一般定義形式如下:
template <typename T> // T 是一個(gè)類型參數(shù)
class MyClass
{
public:
MyClass(T val) : m_val(val) {} // 構(gòu)造函數(shù)也使用類型參數(shù) T
void printVal()
{
std::cout << "value: " << m_val << std::endl;
}
private:
T m_val; // 成員變量使用類型參數(shù) T
};
在這個(gè)例子中,MyClass 是一個(gè)類模板,它有一個(gè)類型參數(shù) T 。T 是一個(gè)占位符,代表一種未指定的數(shù)據(jù)類型。在類模板的定義中,可以像使用普通數(shù)據(jù)類型一樣使用 T 。
要使用類模板,需要?jiǎng)?chuàng)建一個(gè)或多個(gè)該模板的實(shí)例。實(shí)例化類模板時(shí),需要為模板參數(shù)提供具體的數(shù)據(jù)類型。這可以通過在類模板名稱后的尖括號(hào) < > 中指定類型來完成。針對(duì)上面定義的模板類,可以做如下實(shí)例化:
int main()
{
// 實(shí)例化 MyClass 模板,T 被替換為 int
MyClass<int> obj1(1);
obj1.printVal(); // 輸出: value: 1
// 實(shí)例化 MyClass 模板,T 被替換為 string
MyClass<std::string> obj2("hello");
obj1.printVal(); // 輸出: value: hello
return 0;
}
在上面代碼中,為 MyClass 模板提供了兩種數(shù)據(jù)類型:int 和 std::string。每次提供一個(gè)新的數(shù)據(jù)類型,編譯器都會(huì)創(chuàng)建一個(gè)新的類類型。因此,MyClass<int> 和 MyClass<std::string> 是兩種不同的類類型,它們有各自的對(duì)象實(shí)例和方法。
注意事項(xiàng)
(1)類模板的實(shí)例化是隱式的,也就是說,當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),編譯器會(huì)自動(dòng)處理模板的實(shí)例化。
(2)模板參數(shù) T 在類模板的實(shí)例化時(shí)被實(shí)際類型替換,這種替換是在編譯時(shí)完成的,因此不會(huì)增加運(yùn)行時(shí)開銷。
(3)可以為類模板定義多個(gè)類型參數(shù),例如 template <typename T1, typename T2> ,這樣就可以在類中使用兩種不同類型的數(shù)據(jù)。
(4)類模板的實(shí)例化會(huì)產(chǎn)生新的類類型,這些類型之間是相互獨(dú)立的,除了它們共享相同的模板定義外。
3.2 類模板的構(gòu)造函數(shù)和析構(gòu)函數(shù)
在類模板中,構(gòu)造函數(shù)和析構(gòu)函數(shù)的定義與處理常規(guī)類的方式類似。類模板的構(gòu)造函數(shù)用于初始化模板類的對(duì)象,而析構(gòu)函數(shù)用于在對(duì)象生命周期結(jié)束時(shí)釋放資源。
構(gòu)造函數(shù)
構(gòu)造函數(shù)是特殊類型的成員函數(shù),它在創(chuàng)建類的新對(duì)象時(shí)自動(dòng)調(diào)用。類模板的構(gòu)造函數(shù)在實(shí)例化時(shí)會(huì)用實(shí)際的類型參數(shù)替換模板參數(shù),以便正確地進(jìn)行初始化。
下面是一個(gè)類模板的例子,其中包含了構(gòu)造函數(shù):
template <typename T>
class MyClass {
public:
// 構(gòu)造函數(shù)
MyClass(T val) : m_val(val) {}
// 其他成員函數(shù)...
private:
T m_val;
};
在這個(gè)例子中,MyClass 的構(gòu)造函數(shù)接受一個(gè)類型為 T 的參數(shù) val ,并用它來初始化私有成員變量 m_val 。
析構(gòu)函數(shù)
析構(gòu)函數(shù)是當(dāng)對(duì)象的生命周期結(jié)束時(shí)自動(dòng)調(diào)用的特殊成員函數(shù)。在類模板中,析構(gòu)函數(shù)通常用于釋放對(duì)象可能擁有的任何資源,如動(dòng)態(tài)分配的內(nèi)存。
下面是一個(gè)類模板的例子,其中包含了析構(gòu)函數(shù):
template <typename T>
class MyClass
{
public:
// 構(gòu)造函數(shù)
MyClass(T val) : m_val(new T(val)) { }
// 析構(gòu)函數(shù)
~MyClass()
{
delete m_val;
}
// 其他成員函數(shù)...
private:
T* m_val;
};
在這個(gè)例子中,MyClass 的析構(gòu)函數(shù)使用 delete 釋放了動(dòng)態(tài)分配的內(nèi)存。
實(shí)例化時(shí)的構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用
當(dāng)類模板被實(shí)例化并創(chuàng)建對(duì)象時(shí),相應(yīng)的構(gòu)造函數(shù)會(huì)被調(diào)用。同樣,當(dāng)對(duì)象離開其作用域或被顯式刪除時(shí),析構(gòu)函數(shù)會(huì)被調(diào)用。針對(duì)上面定義的模板類,可以做如下實(shí)例化的調(diào)用:
int main()
{
// 實(shí)例化 MyClass 模板,T 被替換為 int
MyClass<int> obj(1); // 調(diào)用 MyClass<int> 的構(gòu)造函數(shù)
// ... obj 被使用 ...
// 當(dāng) obj 離開作用域時(shí),MyClass<int> 的析構(gòu)函數(shù)會(huì)被調(diào)用
return 0;
}
在上面代碼中,obj 是 MyClass 類型的一個(gè)對(duì)象。當(dāng) obj1 被創(chuàng)建時(shí),MyClass 的構(gòu)造函數(shù)會(huì)被調(diào)用,而當(dāng) obj 離開其作用域時(shí),MyClass 的析構(gòu)函數(shù)會(huì)被調(diào)用。
注意:類模板的構(gòu)造函數(shù)和析構(gòu)函數(shù)在處理資源管理和初始化/清理工作時(shí)與常規(guī)類相同,只是它們需要能夠處理模板參數(shù) T 所代表的不同數(shù)據(jù)類型。
3.3 類模板的成員變量和成員函數(shù)
在類模板中,成員變量和成員函數(shù)的概念與常規(guī)類中的相同。成員變量用于存儲(chǔ)類的實(shí)例的狀態(tài),而成員函數(shù)則定義了可以對(duì)這些狀態(tài)執(zhí)行的操作。
成員變量
類模板的成員變量通常使用模板參數(shù) T(或其他模板參數(shù))作為它們的類型。這些變量在類的所有實(shí)例化中都是私有的、受保護(hù)的或公開的,具體取決于它們的訪問修飾符。
下面是一個(gè)類模板的例子,其中包含了由不同訪問修飾符修飾的成員變量:
template <typename T>
class MyClass
{
// 構(gòu)造函數(shù)和其他成員函數(shù)...
// 成員變量
private:
// 私有成員變量
T m_privateVar;
protected:
// 受保護(hù)成員變量
T m_protectedVar;
public:
// 公開成員變量
T m_publicVar;
};
在上面代碼中,m_privateVar、m_protectedVar 和 m_publicVar 都是使用模板參數(shù) T 類型的成員變量。它們的訪問級(jí)別分別是私有、受保護(hù)和公開。
成員函數(shù)
類模板的成員函數(shù)定義了可以在類的實(shí)例上執(zhí)行的操作。這些函數(shù)可以訪問類的成員變量,并且可以使用模板參數(shù) T(或其他模板參數(shù))來執(zhí)行類型無(wú)關(guān)的操作。
如下為樣例代碼:
template <typename T>
class MyClass
{
public:
// 構(gòu)造函數(shù)
MyClass(T val) : m_val(val) {}
// 成員函數(shù)
void setVal(T val) { m_val = val; }
T getVal() const { return m_val; }
// 其他成員函數(shù)...
private:
T m_val;
};
在上面代碼中,setVal 和 getVal 都是成員函數(shù)。setVal 接受一個(gè)類型為 T 的參數(shù),并設(shè)置 value 成員變量的值。getVal 則返回 value 的當(dāng)前值,并且由于它被聲明為 const,所以不能修改類的狀態(tài)。
成員函數(shù)的重載
與常規(guī)類一樣,也可以在類模板中重載成員函數(shù)。這意味著可以定義多個(gè)具有相同名稱但參數(shù)不同的成員函數(shù)。
如下為樣例代碼:
template <typename T1, typename T2>
class MyClass
{
public:
// 重載的成員函數(shù)
void setVal(T1 val) { m_val1 = val; }
// 重載的成員函數(shù)
void setVal(T2 val) { m_val2 = val; }
// 其他成員函數(shù)...
private:
T1 m_val1;
T2 m_val2;
};
在上面代碼中,setVal 被重載了兩次:一次接受 T1 類型的參數(shù),另一次接受 T2 類型的參數(shù)。根據(jù)傳遞給函數(shù)的參數(shù)類型,編譯器會(huì)選擇適當(dāng)?shù)暮瘮?shù)版本進(jìn)行調(diào)用。
3.4 類模板的特化和偏特化
類模板的特化和偏特化是 C++ 模板編程中的兩個(gè)重要概念,它們?cè)试S為特定的類型或一組類型提供定制的模板實(shí)現(xiàn)。
特化
特化是指為模板提供一個(gè)完整的替代實(shí)現(xiàn),該實(shí)現(xiàn)僅適用于一個(gè)特定的類型。當(dāng)需要要改變某個(gè)類型在模板中的行為時(shí),則可以為這個(gè)類型創(chuàng)建一個(gè)特化版本。特化版本會(huì)覆蓋模板的通用實(shí)現(xiàn)。
如下為樣例代碼:
template <typename T>
class MyClass
{
// 通用實(shí)現(xiàn)
};
// 特化版本,僅適用于int類型
template <>
class MyClass<int>
{
// int類型的特化實(shí)現(xiàn)
};
在上面代碼中,MyClass 是一個(gè)模板類,它有一個(gè)通用實(shí)現(xiàn)。然后為 int 類型創(chuàng)建了一個(gè)特化版本,該版本將替代通用實(shí)現(xiàn)。
偏特化
偏特化允許為模板提供一個(gè)定制的實(shí)現(xiàn),該實(shí)現(xiàn)適用于一組特定的類型。與特化不同,偏特化不需要指定所有的模板參數(shù)。
如下為樣例代碼:
template <typename T1, typename T2>
class MyClass
{
// 通用實(shí)現(xiàn)
};
// 偏特化版本,僅適用于T1為int,T2為任意類型的情況
template <typename T2>
class MyClass<int, T2>
{
// int, T2類型的偏特化實(shí)現(xiàn)
};
在上面代碼中,為 MyClass 創(chuàng)建了一個(gè)偏特化版本,該版本僅當(dāng)?shù)谝粋€(gè)模板參數(shù) T1 是 int 類型時(shí)適用,而第二個(gè)模板參數(shù) T2 可以是任意類型。
注意事項(xiàng)
(1)特化和偏特化必須在模板定義之后聲明。
(2)特化和偏特化不能與原始模板在同一個(gè)頭文件中定義。
(3)偏特化不能比原始模板更加通用。例如,如果原始模板接受兩個(gè)類型參數(shù),偏特化就不能只接受一個(gè)。
(4)偏特化在編譯時(shí)的優(yōu)先級(jí)高于特化,也高于原始模板。
使用特化和偏特化可以顯著提高模板的靈活性和效率,但也需要謹(jǐn)慎使用,以避免產(chǎn)生復(fù)雜性和維護(hù)問題。
3.5 類模板與繼承
模板類的繼承與常規(guī)類的繼承非常相似。你可以定義一個(gè)模板類作為基類,然后創(chuàng)建另一個(gè)模板類或非模板類來繼承它。這種繼承允許派生類繼承基類的成員變量和成員函數(shù),同時(shí)還可以添加或覆蓋成員。
模板類繼承非模板類
首先,一個(gè)模板類可以繼承一個(gè)非模板類。這種情況下,模板類將繼承非模板類的所有成員。
如下為樣例代碼:
#include <iostream>
class MyClassWithNonTemplate
{
public:
void withoutTemplateFunc()
{
printf("function without template\n");
}
};
template <typename T>
class MyClassWithTemplateDerived : public MyClassWithNonTemplate
{
public:
void withTemplateFunc()
{
printf("function with template for type : %s\n", typeid(T).name());
}
};
int main() {
MyClassWithTemplateDerived<int> obj;
obj.withoutTemplateFunc(); // 調(diào)用繼承自非模板基類的成員函數(shù)
obj.withTemplateFunc(); // 調(diào)用模板派生類的成員函數(shù)
return 0;
}
上面代碼的輸出為:
function without template
function with template for type : int
模板類繼承模板類
更常見的是,一個(gè)模板類可以繼承另一個(gè)模板類。在這種情況下,派生類模板可以添加、覆蓋或使用基類模板的成員。
如下為樣例代碼:
#include <iostream>
template <typename T>
class MyClassBase
{
public:
void baseFunction()
{
printf("base type : %s\n", typeid(T).name());
}
};
template <typename T1, typename T2=int>
class MyClassDerived : public MyClassBase<T2>
{
public:
void derivedFunction()
{
printf("derived type : %s, base type : %s\n", typeid(T1).name(), typeid(T2).name());
}
};
int main() {
MyClassDerived<double> obj;
obj.baseFunction(); // 調(diào)用模板基類的成員函數(shù)
obj.derivedFunction(); // 調(diào)用模板派生類的成員函數(shù)
return 0;
}
上面代碼的輸出為:文章來源:http://www.zghlxwxcb.cn/news/detail-826913.html
base type : int
derived type : double, base type : int
在這個(gè)例子中,MyClassDerived 繼承自 MyClassBase,并且 MyClassBase 是一個(gè)模板類。MyClassDerived 可以選擇性地提供模板參數(shù) T2,如果沒有提供,則默認(rèn)為 int。
注意事項(xiàng)
(1)模板參數(shù)傳遞:當(dāng)模板類繼承另一個(gè)模板類時(shí),可以選擇傳遞或省略模板參數(shù)。在上面的例子中,MyClassDerived 選擇了傳遞一個(gè)模板參數(shù) T1,并且為 T2 提供了一個(gè)默認(rèn)值 int。
(2)訪問控制:繼承的規(guī)則(公有繼承、保護(hù)繼承、私有繼承)同樣適用于模板類。公有繼承允許派生類訪問基類的公有和保護(hù)成員;保護(hù)繼承允許派生類訪問基類的公有和保護(hù)成員,但將這些成員視為保護(hù)成員;私有繼承允許派生類訪問基類的公有和保護(hù)成員,但將這些成員視為私有成員。
(3)特化和偏特化:當(dāng)涉及到模板類的繼承時(shí),特化和偏特化的規(guī)則同樣適用??梢詾榛惸0寤蚺缮惸0逄峁┨鼗蚱鼗姹尽?br> (4)虛函數(shù)和純虛函數(shù):如果基類模板包含虛函數(shù)或純虛函數(shù),派生類可以選擇覆蓋這些函數(shù)或提供自己的實(shí)現(xiàn)。這對(duì)于創(chuàng)建模板類和派生類的抽象基類尤其有用。文章來源地址http://www.zghlxwxcb.cn/news/detail-826913.html
到了這里,關(guān)于突破編程_C++_高級(jí)教程(模板編程的基礎(chǔ)知識(shí))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!