C++函數(shù)模板與類模板相同與不同介紹
1.模板
1.1何為模板
即模子,生成器。
1.2C++的模板的形式有兩種
函數(shù)模板與類模板。
1.3如何定義一個函數(shù)模板
就像定義函數(shù)一樣,定義一個函數(shù)模板,把函數(shù)中類型抽象出來,
同時告訴編譯器下面的函數(shù)是一個函數(shù)模子或函數(shù)生成器。
1.4語法形式
template + <class T1, class T2 = double, class T3 = int ....> //模板頭中的類型參數(shù)列表也可以有默認值。 T add(T a, T b) { return a + b; }
1.5模板的編譯機制
1.編譯器并不是把模板處理成能夠處理任何類型的函數(shù),而是一個函數(shù)或類的生成器。
2.函數(shù)模板通過具體類型產(chǎn)生不同的函數(shù)(產(chǎn)生了模板函數(shù))
3.編譯器會對函數(shù)模板進行兩次編譯,第一次在聲明的地方對模板本身進行編譯,在調(diào)用的地方對參數(shù)替換后的代碼進行編譯使用函數(shù)模板與真正的函數(shù),誰的調(diào)用效率高呢?當然是真正的函數(shù),因為函數(shù)模板還需要編譯器進行翻譯一遍才能調(diào)用。所以現(xiàn)開發(fā)中并不一定要把所有函數(shù)你都要定義成函數(shù)模板,所以類型替換之后的函數(shù)模板就成了一個函數(shù)實例了,這樣才能調(diào)用。
代碼實例:
#include <iostream> using namespace std; template <class T> T my_add(T a, T b) { return a + b; } int main() { my_add<int>(10,20); my_add<float>(3.14f,5.21f); my_add<double>(5.21,3.14); return 0; }
2.函數(shù)模板
2.1調(diào)用方式
顯式調(diào)用:函數(shù)名后使用<>尖括號指定具體參數(shù)調(diào)用。
using namespace std; template <class T> T my_add(T a, T b) { return a + b; } int main() { my_add<int>(10,20); my_add<float>(3.14f,5.21f); my_add<double>(5.21,3.14); return 0; }
隱式調(diào)用:由編譯器自動根據(jù)參數(shù)推導參數(shù)類型再調(diào)用。
#include <iostream> using namespace std; template <class T> T my_add(T a, T b) { return a + b; } int main() { my_add(10,20); my_add(3.14f,5.21f); my_add(5.21,3.14); return 0; }
2.2函數(shù)模板的特化與調(diào)用優(yōu)先級
當只有基礎(chǔ)模板和特化模板時。
#include <iostream> using namespace std; template <class T> T my_add(T a,T b) { cout<<"這是一個基礎(chǔ)模板"<<endl; return a+b; } template <class T> T my_add(int a,int b) { cout<<"這是一個特化模板"<<endl; return a+b; } int main() { cout<<my_add(10,20)<<endl; return 0; }
結(jié)果圖:
當只有基礎(chǔ)模板和特化模板時,隱式調(diào)用基礎(chǔ)模板。
當有基礎(chǔ)模板和特化模板,還有實例時候。
#include <iostream> using namespace std; template <class T> T my_add(T a,T b) { cout<<"這是一個基礎(chǔ)模板"<<endl; return a+b; } template <class T> T my_add(int a,int b) { cout<<"這是一個特化模板"<<endl; return a+b; } int my_add(int a,int b) { cout<<"這是一個實例"<<endl; return a+b; } int main() { cout<<my_add(10,20)<<endl; return 0; }
結(jié)果圖:
當有基礎(chǔ)模板和特化模板,還有實例時候,隱式調(diào)用用實例。
當有基礎(chǔ)模板和特化模板,還有實例時候,顯示調(diào)用
#include <iostream> using namespace std; template <class T> T my_add(T a,T b) { cout<<"這是一個基礎(chǔ)模板"<<endl; return a+b; } template <class T> T my_add(int a,int b) { cout<<"這是一個特化模板"<<endl; return a+b; } int my_add(int a,int b) { cout<<"這是一個實例"<<endl; return a+b; } int main() { cout<<my_add<int>(10,20)<<endl; return 0; }
結(jié)果圖:
當有基礎(chǔ)模板和特化模板,還有實例時候,顯示調(diào)用用特化模板。
總結(jié):
當有函數(shù)實例時:隱式調(diào)用將直接調(diào)用函數(shù)實例。
如果沒有函數(shù)實例時,隱式調(diào)用將直接調(diào)用函數(shù)模板的基礎(chǔ)模板。
如果使用顯示調(diào)用,當優(yōu)先調(diào)用特化的與類型匹配的函數(shù)模板。
3.可變參函數(shù)模板
3.1概念
所謂的可變參模板是指類型參數(shù)為一一個可變是類型,這個類型使用class...來修飾。
3.2代碼實現(xiàn)(實現(xiàn)一個c中的printf的函數(shù))
#include <iostream> using namespace std; void printf() { } template <class Firstarg,class... Arg> void printf(Firstarg firstarg, Arg... arg) { cout<<firstarg; printf(arg...); } int main() { printf("lisi","cc"); return 0; }
結(jié)果圖:
4.類模板
4.1類模板的定義形式
注意:在使用類模板時,不存在編譯推導類型,必須手動指定具體類型。
template <class T1, class T2, class T3 ...> //class修飾符也可使用typename來修飾。 class + 類名 { //類模板的模板體。 private: //類模板中的屬性。 public: //類中的方法 protected: };
4.2代碼實例
#include <iostream> using namespace std; template <class T1,class T2> class A { T1 name; T2 age; public: A(T1 name,T2 age) { this->age=age; this->name=name; } void show_info() { cout<<"name="<<name<<",age="<<age<<endl; } }; int main() { // A<string,int> a("lisi",20); // a.show_info(); A<string,int>* a=new A<string,int>("lisi",20); a->show_info(); return 0; }
結(jié)果圖:
5.類模板中的特殊屬性的初始化方式及繼承與多態(tài)
5.1代碼實例
#include <iostream> using namespace std; template <class T1,class T2> class A { T1 name; T2 age; public: A(T1 name,T2 age) { this->name=name; this->age=age; } virtual void show_info() { cout<<"name="<<this->name<<",age"<<age<<endl; } void set_name(T1 name) { this->name=name; } T1 get_name() { return this->name; } void set_age(T2 age) { this->age=age; } T2 get_age() { return this->age; } }; template <class T1,class T2,class T3> class B:public A<T1,T2> { const int id; static int count; public: B(T1 name,T2 age,T3 _id):id(_id),A<T1,T2>(name,age) { } void show_info() { cout<<"id="<<this->id<<",name="<<this->get_name()<<",age"<<this->get_age()<<endl; } }; int main() { //1.棧上 B<string,int,int> b("lisi",20,1001); b.show_info(); //2.堆上 B<string,int,int>* b1=new B<string,int,int>("zhangsan",29,1002); b1->show_info(); //3.實現(xiàn)多態(tài) A<string,int>* a=new B<string,int,int>("wangwu",50,1003); a->show_info(); return 0; }
結(jié)果圖:
5.2使用類模板去實現(xiàn)一個數(shù)據(jù)結(jié)構(gòu)
實現(xiàn)一個順序棧模板
首先我們使用一下多文件編程,類似于c的那種,我們會發(fā)現(xiàn)問題如下:
main.cpp文件:
#include <iostream> #include "socket.h" using namespace std; int main() { socket<int> s(2); return 0; }
stack.h文件:
#ifndef SOCKET_H #define SOCKET_H using namespace std; #include <iostream> template <class T> class socket { T* m_date; int len; int max_size; public: //構(gòu)造 socket(int _len); //析構(gòu) ~socket(); //入棧 void push(const socket& other); //出棧 void out(); //獲取棧頂?shù)闹? T get_out(); //判斷是否為空 bool is_empty(); }; #endif // SOCKET_H
stack.cpp文件:
#include "socket.h" template <class T> socket<T>::socket(int _max_size) { this->m_date=new T[len]; this->len=0; this->max_size=_max_size; }
結(jié)果圖:
結(jié)果分析:如圖所以,結(jié)果告訴我們無法連接到構(gòu)造函數(shù),這是由于我們使用的是模板類,模板類需要被編譯兩次,如果我們像這樣把stack.cpp和stack.h分開寫的話,stack.cpp里面的模板只被編譯了一次,所以我們無法連接到構(gòu)造函數(shù)。
使分文件編程的方式實現(xiàn)一個模板棧:
在C++分文件編程時,在業(yè)內(nèi)常用的一種文件標準是后綴為.hpp的模板文件。
代碼實現(xiàn):
stack.cpp文件:
#ifndef STACK_HPP #define STACK_HPP using namespace std; #include <iostream> template <class T> class Stack { T* my_data; int len; int max_size; public: //構(gòu)造函數(shù) Stack(int _max_size); //析構(gòu)函數(shù) ~Stack(); //入棧 void push(const int& other); //出棧 void out_data(); //獲取棧頂?shù)闹? T get_data(); //判斷是否為空 bool is_empty(); }; #endif // STACK_HPP template <class T> Stack<T>::Stack(int _max_size) { this->my_data=new int[_max_size]; this->len=0; this->max_size=_max_size; } template <class T> Stack<T>::~Stack() { if(this->my_data!=nullptr){ delete this->my_data; } } template <class T> void Stack<T>::push(const int& other) { if(this->max_size<len){ return; } my_data[len]=other; ++(this->len); } template <class T> void Stack<T>::out_data() { if(len<=0){ return; } --(this->len); } template <class T> T Stack<T>::get_data() { return this->my_data[len-1]; } template <class T> bool Stack<T>::is_empty() { if(this->len==0){ return true; } return false; }
main.cpp文件:
#include <iostream> #include "stack.hpp" using namespace std; int main() { Stack<int> s(12); s.push(1); s.push(2); s.push(3); while(!s.is_empty()){ cout<<s.get_data()<<endl; s.out_data(); } return 0; }
結(jié)果圖:
分析:因為這次我們把函數(shù)的實現(xiàn)放在了hpp文件里面,當我們調(diào)用頭文件的時候問編譯一次,還有就是當調(diào)用聲明的時候也會編譯一次,所以就達到了類模板的使用要求,所以這次我們就可以鏈接到。
5.3類模板的特化
#include <iostream> using namespace std; template<class T1> class A { public: A() { cout<<"A的基礎(chǔ)模板"<<endl; } }; template <> class A <int> { public: A() { cout<<"A的特化模板"<<endl; } }; template <class T2,class T3> class B { public: B() { cout<<"B的基礎(chǔ)模板"<<endl; } }; template <class T2> class B<T2,float> { public: B() { cout<<"B的偏化模板"<<endl; } }; int main() { A<float> a; A<int> a1; B<int ,int> b1; B<int ,float> b2; return 0; }
結(jié)果圖:
分析:當使用類模板去定義對象時,因為具體指定使參數(shù)類型,所以他將優(yōu)先調(diào)用與之指定類型相匹配的特化或偏特化版本。否則,將直接調(diào)用全特化。
5.4C++中類模板中的內(nèi)嵌類
內(nèi)嵌類一般情況下是為外圍類而服務(wù):比如說:STL容器中所提供的迭代器就是一種內(nèi)嵌類。內(nèi)嵌類并不是對外公開的,只做為外圍類的一個輔助類。隱藏在外圍類的內(nèi)部,對外不可以見。只能通過::域名訪問的形式,才能訪問到。
代碼實例:
#include <iostream> using namespace std; template <typename T> class A { public: class B { int a = 100; int b = 200; static B* c; }; }; template <class T> typename A<T>::B* A<T>::B::c = nullptr; int main() { A<int> a; cout << sizeof (a) << endl; A<float>::B b1; cout << sizeof(b1) <<endl; return 0; }
內(nèi)嵌類需要注意的幾點內(nèi)容:
1.內(nèi)嵌類可以訪問定義在外圍類(enclosing class)中的靜態(tài)實例變量。外圍類不可以訪問嵌套類的成員.
2.不能從內(nèi)嵌類中訪問外部類的非靜態(tài)成員.
3.可以在外部通過作用域限定符調(diào)用.
到此這篇關(guān)于C++函數(shù)模板與類模板相同與不同介紹的文章就介紹到這了,更多相關(guān)C++函數(shù)模板與類模板內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ Custom Control控件向父窗體發(fā)送對應的消息
這篇文章主要介紹了C++ Custom Control控件向父窗體發(fā)送對應的消息的相關(guān)資料,需要的朋友可以參考下2015-06-06