讀書筆記_Effective_C++_條款四十四:將與參數無關的代碼抽離template

標題上說「將與參數無關的代碼抽離template」,這裏的參數既能夠指類型,也能夠是非類型,咱們先來看看非類型的狀況。算法

假定咱們要爲矩陣寫一個類,這個矩陣的行列元素個數相等,是一個方陣,於是咱們能夠對之求逆運算。由於方陣的元素能夠有多種類型,同時方陣的維數(方陣大小)也能夠不一樣,像下面這樣,咱們使用了模板:函數

 1 template <class T, size_t n>
 2 class SquareMatrix
 3 {
 4 public:
 5     void Invert();
 6 };
 7 
 8 int main()
 9 {
10     SquareMatrix<int, 10> a;
11     SquareMatrix<int, 5> b;
12 }

模板既能夠指定類型,也能夠指定其餘參量,好比這裏的size_t,用來表示方陣的維數。程序看起來是沒有問題的,編譯也是經過的,但從代碼優化上看,仍是有空間能夠作的。a和b雖然都是元素爲int型的方陣,但由於方陣維數不一樣,於是生成了兩個Invert函數,這兩個Invert函數的代碼只是在循環個數上不一樣(取覺於方陣維數n),但算法思想徹底是同樣的。工具

爲了防止編譯器生成冗餘的代碼,咱們能夠將Invert抽離這裏,變成一個以n爲參數的函數,像下面這樣:優化

 1 class SquareMatrixBase
 2 {
 3 public:
 4     SquareMatrixBase(T* p) : DataPointer(p){}
 5     void Invert(size_t n){}
 6 private:
 7     T* DataPointer;
 8 };
 9 
10 
11 template <class T, size_t n>
12 class SquareMatrix: private SquareMatrixBase<T>
13 {
14 public:
15     SquareMatrix() : SquareMatrixBase(Data)
16     {}
17     void Invert()
18     {
19         SquareMatrixBase::Invert(n);
20     }
21 private:
22     T Data[n * n];
23 };

這裏咱們定義了一個BaseSquareMatrix類,這個類能夠視爲一個工具類,由於SquareMatrix是private繼承於它的,咱們把算法一致、只與維數n相關的算法函數都放在BaseSquareMatrix中,且將n做爲它的Invert()函數的形參,爲了使BaseSquareMatrix能夠訪問數據,從而求逆運算,咱們聲明瞭它的成員指針,這個指針將會在構造時指向子類的數據存儲空間。spa

子類SquareMatrix沒有大變化,只是在Invert的時候,用了一句代碼就搞定了——調用父類的Invert函數,並把維數n傳過去。指針

這樣在main函數中,針對類型都是int,但矩陣維數不一樣的狀況,Invert中生成的冗餘代碼很是少(只有一句話),父類也由於模板參數與維數沒法,因此也只生成一份。從這個角度來看,將與參數無關的代碼抽離template起到了減小代碼冗餘度的優化做用。code

 

目前只是說將與類型無關的代碼進行抽離(造一個父類,把算法相同的部分提取出來,放到父類),對於不一樣類型,其實也能夠經過void*來實。好比STL,要想令咱們使用list<int*>,list<const int*>生成的代碼冗餘度保持很低,這就須要在相應的函數裏面,將之鏈到父類的一個公共實現版本里面,這個版本的形參是void*。blog

 

最後總結一下:繼承

1. Template生成多個classes與多個函數,因此任何template代碼都不應與某個形成膨脹的template參數產生相依關係。編譯器

2. 因非類型模板參數而形成的代碼膨脹,每每能夠消除,作法是以函數參數或者class成員變量替換template參數。

3. 因類型而形成的代碼膨脹,也能夠下降,作法是讓帶有徹底相同二進制表述的具現類型共享實現碼。

相關文章
相關標籤/搜索