C++中的模板(上)
模板參數和函數參數是很像的,函數參數定義的形參對象,而模板參數定義的是類型.
模板分為函數模板和類模板
函數模板
一個交換兩個數的函數模板:
template<class T> // 此處typename和class是等價的
void Swap(T &a, T &b)
{T temp = a;a = b;b = temp;
}
可以給這里的函數傳遞任何類型的參數.
任何類型的值都是可以傳遞的:
void Test1()
{int a = 1, b = 2;Swap(a, b);cout << a << " " << b << endl;double c = 1.1, d = 2.2;Swap(c, d);cout << c << " " << d << endl;
}
這里的ab和cd變量表面上調用的是同一個函數,實際上調用的函數是不同的,因為編譯器會根據類型自動推斷,如果推斷出不同的類型就會在編譯的時候生成不同的函數.
編譯器這個生成函數的過程稱之為模板的實例化.
用不同的參數實例化函數模板時,成為函數模板的實例化.模板參數實例化分為:隱式實例化和顯式實例化.
函數模板可以顯式的實例化也可以通過傳遞參數自動推出模板參數的類型,但是類模板都是顯式實例化.
函數模板的顯式實例化:
template<class T>
T Add(T a, T b)
{return a + b;
}
void Test2()
{cout<<Add(1,2)<<endl; // 隱式實例化,通過參數傳遞自動推出模板參數的類型cout<<Add<int>(1,2)<<endl; // 顯式實例化.cout<<Add<double>(1.1,2)<<endl;
}
注意:
普通函數和模板函數是可以同時存在的.例如:
// 普通函數 int Add(int a,int b) {return a + b; } // 函數模板 template<class T> int Add(const T& a,const T& b) {return a + b; }
這樣函數在調用的時候,會自動根據最佳類型進行匹配.
類模板
類模板的寫法與函數模板類似的:
template<class T>
class Stack
{
public:Stack(int capacity = 3):_capacity(capacity){cout<<"Stack<T>::Stack(int capacity)"<<endl;_a = new T[_capacity];_top = 0;}~Stack();
private:T* _a;int _top;int _capacity;
};
-
對于沒有使用模板語法的類的類名就是就是它的類型.例如以下的例子:
class A { private: int _a; public:} int main() {A a; }
A類就是一個沒有使用任何類模板語法的普通類,a對象對應的類型就是A.
-
而對于使用了類模板的類來講,類的類型不僅僅是類名,還需要包含類模板中的模板類型,例如:
template<class T> class Stack { public:Stack(int capacity = 3):_capacity(capacity){cout<<"Stack<T>::Stack(int capacity)"<<endl;_a = new T[_capacity];_top = 0;}~Stack(); private:T* _a;int _top;int _capacity; }; int main() {Stack<int> stack1;Stack<double> stack2;return 0; }
例如這個stack1對象的類型就是
Stack<int>
,這個stack2對象的類型就是Stack<double>
,而Stack<int>
和Stack<double>
是不同的類型.
模板類的聲明與定義分離
模板類中方法的聲明與普通類中方法的聲明是一樣的.
但是在方法的定義的前面要指定類的類型(注意:模板類的類型是類名<類型>),同時需要在方法定義的上面一排聲明模板參數.例如要將Stack類的構造方法的聲明與定義分離的做法:
template<class T>
class Stack
{
public:// 方法聲明Stack(int capacity = 3);~Stack();void Print();
private:T* _a;int _top;int _capacity;
};// 方法定義
template<class T> // 聲明模板參數
Stack<T>::Stack(int capacity )
:_capacity(capacity)
{ cout<<"Stack<T>::Stack(int capacity)"<<endl;_a = new T[_capacity];_top = 0;
}
// 方法定義
template<class T>
Stack<T>::~Stack()
{delete[] _a;_a = nullptr;_top = 0;_capacity = 0;cout<<"Stack<T>::~Stack()"<<endl;
}
// 方法定義
template<class T>
void Stack<T>::Print()
{cout<<"top = "<<_top<<endl;
}
對于普通類而言,類中方法的聲明與定義是可以在不同的文件中的.
但是對于模板類,方法的聲明與定義是不支持在不同文件中的.不能像普通類那樣將類的聲明放到頭文件中,將方法的定義放在源文件中.