C++函式指標、函式物件與C++11 function物件對比分析
-
函式指標怎麼宣告?能用來做什麼?什麼時候用?
-
函式指標變數名稱一定要和函式名字一樣嗎?一個函式只能定義一個函式指標嗎?
-
給函式指標變數初始化,獲取函式的地址時,有幾種方式?可以不加取址&符號嗎?想要傳入另外一個函式,一定要提前定義嗎?
-
函式物件的實質是什麼?怎麼理解這個東西?
-
怎麼呼叫函式物件?
-
函式物件和函式指標的比較?
-
C++11中的function函式物件又是什麼,是用來幹什麼的?
1.函式指標
指向函式地址的指標變數,
在C編譯時,每一個函式都有一個入口地址,那麼這個指向這個函式的函式指標便指向這個地址。
函式指標主要由以下兩方面的用途:
呼叫函式和用作函式引數。
宣告方法:
函式返回型別 + (指標變數名)+ (形參列表)
//例子 int func(int x); int (*func) (int x);
使用例子:
#include<iostream> #include<cstdlib> #include<vector> using namespace std; int AddFunc(int a, int b) { return a + b; } int main() { int (*Add1)(int a,int b); int (*Add2)(int a,int b); Add1 = &AddFunc; Add2 = AddFunc;//兩種函式指標賦初值方法,可以加取地址符也可以不加 cout << (*Add1)(3,2)<<endl; // 5 cout<<Add1(3,2)<<endl;//輸出可以加*,也可以不加 system("pause"); return 0; }
2.函式物件
C++函式物件實質上是操作符過載,實現了對()操作符的過載。C++函式物件不是函式指標。但是,在程式程式碼中,它的呼叫方式與函式指標一樣,後面加個括號就可以了。
函式物件例子
int AddFunc(int a, int b) { return a + b; } class Add { public: const int operator()(const int a,const int b) { return a+b; } }; int main() { //函式指標 int (*Add1)(int a,int b); int (*Add2)(int a,int b); Add1 = &AddFunc; Add2 = AddFunc;//兩種函式指標賦初值方法 cout << (*Add1)(3,2)<<endl; // 5 cout<<Add1(3,2)<<endl;//輸出可以加*,也可以不加 //函式物件 Add addFunction; cout<<addFunction(2,3)<<endl;//呼叫類的過載操作符()方法 system("pause"); return 0; }
函式物件與函式指標比較
函式物件可以把附加物件儲存在函式物件中是它最大的優點。
另外,C++函式物件還有一個函式指標無法匹敵的用法:可以用來封裝類成員函式指標。
它的弱勢也很明顯,它雖然用起來象函式指標,但畢竟不是真正的函式指標。在使用函式指標的場合中,它就無能為力了。例如,你不能將函式物件傳給qsort函式!因為它只接受函式指標。
3.C++11 function函式物件
介紹:類模版std::function是一種通用、多型的函式封裝。std::function可以對任何可以呼叫的實體進行封裝,這些目標實體包括普通函式、Lambda表示式、函式指標、以及其它函式物件等。std::function物件是對C++中現有的可呼叫實體的一種型別安全的包裹(我們知道像函式指標這類可呼叫實體,是型別不安全的)。
通常std::function是一個函式物件類,它包裝其它任意的函式物件,被包裝的函式物件具有型別為T1, …,TN的N個引數,並且返回一個可轉換到R型別的值。std::function使用 模板轉換建構函式接收被包裝的函式物件;特別是,閉包型別可以隱式地轉換為std::function。
也就是說,通過std::function對C++中各種可呼叫實體(普通函式、Lambda表示式、函式指標、以及其它函式物件等)的封裝,形成一個新的可呼叫的std::function物件;讓我們不再糾結那麼多的可呼叫實體。一切變的簡單粗暴。
C++11 function物件示例:
#include <functional>
#include <iostream>
using namespace std;
std::function< int(int)> Functional;
// 普通函式
int TestFunc(int a)
{
return a;
}
// Lambda表示式
auto lambda = [](int a)->int{ return a; };
// 仿函式(functor)
class Functor
{
public:
int operator()(int a)
{
return a;
}
};
// 1.類成員函式
// 2.類靜態函式
class TestClass
{
public:
int ClassMember(int a) { return a; }
static int StaticMember(int a) { return a; }
};
int main()
{
// 普通函式
Functional = TestFunc;
int result = Functional(10);
cout << "普通函式:"<< result << endl;
// Lambda表示式
Functional = lambda;
result = Functional(20);
cout << "Lambda表示式:"<< result << endl;
// 仿函式
Functor testFunctor;
Functional = testFunctor;
result = Functional(30);
cout << "仿函式:"<< result << endl;
// 類成員函式
TestClass testObj;
Functional = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);
result = Functional(40);
cout << "類成員函式:"<< result << endl;
// 類靜態函式
Functional = TestClass::StaticMember;
result = Functional(50);
cout << "類靜態函式:"<< result << endl;
return 0;
}
對於各個可呼叫實體轉換成std::function型別的物件,上面的程式碼都有,執行一下程式碼,閱讀一下上面那段簡單的程式碼。總結了簡單的用法以後,來看看一些需要注意的事項:
關於可呼叫實體轉換為std::function物件需要遵守以下兩條原則:
(1)轉換後的std::function物件的引數能轉換為可呼叫實體的引數;
(2)可呼叫實體的返回值能轉換為std::function物件的返回值。
std::function物件最大的用處就是在實現函式回撥,使用者需要注意,它不能被用來檢查相等或者不相等,但是可以與NULL或者nullptr進行比較。
function物件好處
std::function實現了一套型別消除機制,可以統一處理不同的函式物件型別。以前我們使用函式指標來完成這些;現在我們可以使用更安全的std::function來完成這些任務。
附加:
void visit(T &); void visit(T &t) { //遍歷功能 return; } //利用函式指標機制,只讀(訪問)或區域性性修改,傳入一個函式作為引數(使用過程中自己定義) template <typename T> void Vector<T>::traverse(void(*visit)(T&)) //引數為函式指標,可以不用提前定義函式指標變數 { for (int i = 0; i < _size; i++) { visit(_elem[i]);//引數為向量元素的引用,通過該函式可直接訪問或修改向量元素 } } template <typename T> template <typename VST> //操作器 void Vector<T>::traverse(VST& visit) //利用函式物件機制,可全域性性修改 { for (int i = 0; i < _size; i++) visit(_elem[VST]);//什麼意思? }