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)先級
當只有基礎模板和特化模板時。
#include <iostream>
using namespace std;
template <class T>
T my_add(T a,T b)
{
cout<<"這是一個基礎模板"<<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;
}結果圖:

當只有基礎模板和特化模板時,隱式調(diào)用基礎模板。
當有基礎模板和特化模板,還有實例時候。
#include <iostream>
using namespace std;
template <class T>
T my_add(T a,T b)
{
cout<<"這是一個基礎模板"<<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;
}結果圖:

當有基礎模板和特化模板,還有實例時候,隱式調(diào)用用實例。
當有基礎模板和特化模板,還有實例時候,顯示調(diào)用
#include <iostream>
using namespace std;
template <class T>
T my_add(T a,T b)
{
cout<<"這是一個基礎模板"<<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;
}結果圖:

當有基礎模板和特化模板,還有實例時候,顯示調(diào)用用特化模板。
總結:
當有函數(shù)實例時:隱式調(diào)用將直接調(diào)用函數(shù)實例。
如果沒有函數(shù)實例時,隱式調(diào)用將直接調(diào)用函數(shù)模板的基礎模板。
如果使用顯示調(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;
}結果圖:

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;
}結果圖:

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;
}結果圖:

5.2使用類模板去實現(xiàn)一個數(shù)據(jù)結構
實現(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:
//構造
socket(int _len);
//析構
~socket();
//入棧
void push(const socket& other);
//出棧
void out();
//獲取棧頂?shù)闹?
T get_out();
//判斷是否為空
bool is_empty();
};
#endif // SOCKET_Hstack.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;
}結果圖:

結果分析:如圖所以,結果告訴我們無法連接到構造函數(shù),這是由于我們使用的是模板類,模板類需要被編譯兩次,如果我們像這樣把stack.cpp和stack.h分開寫的話,stack.cpp里面的模板只被編譯了一次,所以我們無法連接到構造函數(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:
//構造函數(shù)
Stack(int _max_size);
//析構函數(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;
}結果圖:

分析:因為這次我們把函數(shù)的實現(xiàn)放在了hpp文件里面,當我們調(diào)用頭文件的時候問編譯一次,還有就是當調(diào)用聲明的時候也會編譯一次,所以就達到了類模板的使用要求,所以這次我們就可以鏈接到。
5.3類模板的特化
#include <iostream>
using namespace std;
template<class T1>
class A
{
public:
A()
{
cout<<"A的基礎模板"<<endl;
}
};
template <>
class A <int>
{
public:
A()
{
cout<<"A的特化模板"<<endl;
}
};
template <class T2,class T3>
class B
{
public:
B()
{
cout<<"B的基礎模板"<<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;
}結果圖:

分析:當使用類模板去定義對象時,因為具體指定使參數(shù)類型,所以他將優(yōu)先調(diào)用與之指定類型相匹配的特化或偏特化版本。否則,將直接調(diào)用全特化。
5.4C++中類模板中的內(nèi)嵌類
內(nèi)嵌類一般情況下是為外圍類而服務:比如說: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)用.
到此這篇關于C++函數(shù)模板與類模板相同與不同介紹的文章就介紹到這了,更多相關C++函數(shù)模板與類模板內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++ Custom Control控件向父窗體發(fā)送對應的消息
這篇文章主要介紹了C++ Custom Control控件向父窗體發(fā)送對應的消息的相關資料,需要的朋友可以參考下2015-06-06

