Tr1::function的介紹
它是一個類模板,類的成員變量是一個函數指針。可以把它看作一個智能函數指針(和shared_ptr智能指針對比着理解)。
一. 頭文件
#include<functional>
二. 使用
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
void foo(int i){cout<<"aaa"<<endl;}
void (*p)(int)=foo;
int _tmain(int argc, _TCHAR* argv[])
{
function<void (int)> fm;
fm=foo;
(*p)(2);
fm(2);
return 0;
}
可以看出它和函數指針很像,但是它具有很多函數指針做不到的事情。下面慢慢說。
1. 定義一個function對象。
由於function是一個類模板,所以使用起來,首先定義一個類的對象。
Function <void (int)> fm;-----<>中第一個參數是要綁定函數的返回類型,第二個參數是要綁定的函數的參數列表。注意使用小括號括起來。
2. 像函數指針一樣,這個指針需要指向某個函數。
fm=function<void (int)>(foo);
3. 由於類模板function重載了()符號。所以使用起來比函數指針更易用。
Fm(2);
下面說一下爲什麼要有tr1::function.也就是它相對於函數指針的優點:
1. 綁定的函數的類型
函數指針只能綁定普通的外部函數。而tr1::function可以綁定各種函數類型。
(1) 外部普通函數和類的static函數
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
class A{
public:
static void foo(inti){cout<<"aaa"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
function<void (int)>fm(A::foo);
//function<void (int)> fm;fm=function<void(int)>(A::foo); also OK
void (*p)(inti)=A::foo();//error
fm(2);
return 0;
}
因爲外部函數和類的static很相似,所以使用起來也很相似。
(2)類的非static成員函數。
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
class A{
public:
void foo(int i){cout<<"aaa"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
A b;
function<void (int)>fm=bind(&A::foo,b,tr1::placeholders::_1);//OK
//function<void (int)> fm=b.foo();//error
fm(2);
return 0;
}
注意必須是&A::foo(),這個符號&不能少,這是由function決定的。這裏bind中的foo只是接受一個參數,而實際上是需要兩個參數,因爲static函數是沒有對象就存在的,而非static成員函數必須有對象之後才能存在,所以這個成員函數需要指明是哪個對象的成員函數。
(3) 綁定虛函數,呈現多態
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
class A{
public:
virtual void foo(int i){cout<<"A"<<endl;}
void fun(){
function<void (int)>fm=bind(&A::foo,this,tr1::placeholders::_1);
fm(2);//這裏和直接調用foo();效果是一樣的。並沒有改變它的多態性質
}
};
class B:public A
{
public:void foo(inti){cout<<"B"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
B b;
b.fun();
return 0;
}
其實這裏並不是function的什麼特殊性質,而只是function是一個普通的類而已,不是因爲它而改變多態性質。這裏和直接調用foo();的效果一樣。
2. 構造函數中的參數
(1) 首先是函數名,這個上面已經講過
(2) 可以是一個函數對象!(函數對象就是一個重載了操作符”()”的類,這樣類的對象可以:a(…);使用起來很像函數,所以叫做函數對象)
//t.cpp
#include "stdafx.h"
#include<iostream>
#include<functional>
using namespace std;
class A{
public:
void operator()(int i){cout<<"A"<<endl;
}
void foo(){}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
function<void (int)> fm(a);
fm(2);
return 0;
}
注意這裏,居然可以把一個類對象放到function裏!這好像違反了function函數指針的原意。但是注意:由於function沒有提供返回它擁有的東西的函數,所以這裏只能fm(2);來調用類中的重載()函數。不能調用類中的其他函數。所以它還是一個函數指針,只是這個指針指向的函數是一個類中的重載()函數罷了。
3. function類模板的其他幾個member函數
(1) assign函數,爲這個函數指針分配一個函數實體。
(2) swap函數,交換兩個函數指針擁有的東西
(3) target函數,測試本函數指針指向的函數類型是不是爲指定類型
(4) target_type函數,獲取函數指針指向的函數的類型信息
不常用,也不好用,所以瞭解即可。
總結:其實function和函數指針很像,只是比函數指針能多指向一些特別的函數而已。
普通函數指針只能指向普通的外部函數
Function可以指向:外部函數,類的static函數,類的非static函數,類的virtual函數,類的對象(函數對象)。