C++中有一個重要特性,那就是模板類型。相似於Objective-C中的泛型。C++經過類模板來實現泛型支持。ios
類模板,能夠定義相同的操做,擁有不一樣數據類型的成員屬性。
一般使用template來聲明。告訴編譯器,碰到T不要報錯,表示一種泛型.
以下,聲明一個普通的類模板:函數
template <typename T> class Complex{ public: //構造函數 Complex(T a, T b) { this->a = a; this->b = b; } //運算符重載 Complex<T> operator+(Complex &c) { Complex<T> tmp(this->a+c.a, this->b+c.b); return tmp; } private: T a; T b; } int main() { //對象的定義,必須聲明模板類型,由於要分配內容 Complex<int> a(10,20); Complex<int> b(20,30); Complex<int> c = a + b; return 0; }
在模板類的繼承中,須要注意如下兩點:this
若是父類自定義了構造函數,記得子類要使用構造函數列表來初始化spa
template <typename T> class Parent{ public: Parent(T p) { this->p = p; } private: T p; }; //若是子類不是模板類,須要指明父類的具體類型 class ChildOne:public Parent<int>{ public: ChildOne(int a,int b):Parent(b) { this->cone = a; } private: int cone; }; //若是子類是模板類,能夠用子類的泛型來表示父類 template <typename T> class ChildTwo:public Parent<T>{ public: ChildTwo(T a, T b):Parent<T>(b) { this->ctwo = a; } private: T ctwo; };
普通模板函數和友元模板函數,聲明和定義都寫在類的內部,也不會有什麼報錯。正常。code
template <typename T> class Complex { //友元函數實現運算符重載 friend ostream& operator<<(ostream &out, Complex &c) { out<<c.a << " + " << c.b << "i"; return out; } public: Complex(T a, T b) { this->a = a; this->b = b; } //運算符重載+ Complex operator+(Complex &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } //普通加法函數 Complex myAdd(Complex &c1, Complex &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; } private: T a; T b; }; int main() { Complex<int> c1(1,2); Complex<int> c2(3,4); Complex<int> c = c1 + c2; cout<<c<<endl; return 0; }
若是普通的模板函數聲明在類的內部,定義在類的外部,無論是否處於同一個文件,就跟普通的函數同樣,不會出現任何錯誤提示。可是若是是友元函數就會出現報錯,是由於有二次編譯這個機制存在。對象
在編譯器進行編譯的時候,編譯器會產生類的模板函數的聲明,當時實際確認類型後調用的時候,會根據調用的類型進行再次幫咱們生成對應類型的函數聲明和定義。咱們稱之爲二次編譯。一樣,由於這個機制,會常常報錯找不到類的函數的實現。在模板類的友元函數外部定義時,也會出現這個錯誤。解決方法是 「 類的前置聲明和函數的前置聲明 」。
按照普通模板函數的樣式處理友元函數blog
#include <iostream> using namespace std; template <typename T> class Complex { //友元函數實現運算符重載 friend ostream& operator<<(ostream &out, Complex<T> &c); public: Complex(T a, T b); //運算符重載+ Complex<T> operator+(Complex<T> &c); //普通加法函數 Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2); private: T a; T b; }; //友元函數的實現 template <typename T> ostream& operator<<(ostream &out, Complex<T> &c) { out<<c.a << " + " << c.b << "i"; return out; } //函數的實現 template <typename T> Complex<T>::Complex(T a, T b) { this->a = a; this->b = b; } template <typename T> Complex<T> Complex<T>::operator+(Complex<T> &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } template <typename T> Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; } int main() { Complex<int> c1(1,2); Complex<int> c2(3,4); Complex<int> c = c1 + c2; cout<<c<<endl; return 0; }
友元函數的定義寫在類的外部--錯誤信息繼承
Undefined symbols for architecture x86_64: "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Complex<int>&)", referenced from: _main in demo1.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
上面的錯誤信息,就是典型的二次編譯的錯誤信息,找不到友元函數的函數實現。因此,若是友元模板函數的定義寫在函數的外部,須要進行類和函數的前置聲明,來讓編譯器找到函數的實現內存
類的前置聲明
友元模板函數的前置聲明
友元模板函數聲明須要增長泛型支持get
類的聲明和實現,分別在不一樣的文件下,須要增長一個hpp文件支持。或者儘可能將模板函數與模板友元放在一個文件下。
類的聲明與函數的聲明寫在.h文件
類的實現及函數的實現寫在.cpp文件
將.cpp文件改爲.hpp文件
在主函數中調用.hpp文件,而不是引用.h文件
若是碰到.h和.hpp文件都存在的狀況下,引用.hpp文件。
demo2.h文件
存放類的聲明和函數的聲明
#include <iostream> using namespace std; //類的前置聲明 template <typename T> class Complex; //友元函數的聲明 template <typename T> ostream& operator<<(ostream &out, Complex<T> &c); template <typename T> class Complex { //友元函數實現運算符重載 friend ostream& operator<< <T> (ostream &out, Complex<T> &c); public: Complex(T a, T b); //運算符重載+ Complex<T> operator+(Complex<T> &c); //普通加法函數 Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2); private: T a; T b; };
demo2.hpp文件
包括模板函數的實現
#include "demo2.h" //友元函數的實現 template <typename T> ostream& operator<<(ostream &out, Complex<T> &c) { out<<c.a << " + " << c.b << "i"; return out; } //函數的實現 template <typename T> Complex<T>::Complex(T a, T b) { this->a = a; this->b = b; } template <typename T> Complex<T> Complex<T>::operator+(Complex<T> &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } template <typename T> Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; }
main.cpp文件
須要調用hpp文件
#include <iostream> using namespace std; #include "demo2.hpp" int main() { Complex<int> c1(1,2); Complex<int> c2(3,4); Complex<int> c = c1 + c2; cout<<c<<endl; return 0; }