一、函數(shù)對(duì)象中存儲(chǔ)狀態(tài)
1、函數(shù)對(duì)象中存儲(chǔ)狀態(tài)簡(jiǎn)介
在 C++ 語(yǔ)言中 , 函數(shù)對(duì)象 / 仿函數(shù) 可以像函數(shù)一樣被調(diào)用 , 并且 其 還具有類的特征 , 可以 通過(guò) 繼承 和 重載 來(lái) 修改 重載函數(shù)調(diào)用操作符函數(shù) 的行為 ;
函數(shù)對(duì)象 / 仿函數(shù) 通常是通過(guò) 定義一個(gè)類 , 然后為這個(gè)類 重載 函數(shù)調(diào)用操作符 () 來(lái)實(shí)現(xiàn)的 ;
函數(shù)對(duì)象的一個(gè)重要特性是 " 可以存儲(chǔ)狀態(tài) " ; 這意味著你可以 在類的成員變量中存儲(chǔ)數(shù)據(jù) , 這些數(shù)據(jù)可以 在函數(shù)調(diào)用之間保持不變 ;
普通的函數(shù) 是 無(wú)法存儲(chǔ)狀態(tài) 的 , 因?yàn)?普通函數(shù) 中 局部變量 在函數(shù)執(zhí)行完成后 , 自動(dòng)銷毀 ;
函數(shù)對(duì)象 / 仿函數(shù) 的一個(gè)主要優(yōu)勢(shì)是它們可以擁有狀態(tài) , 而普通函數(shù)則不能 ;
這使得 " 函數(shù)對(duì)象 / 仿函數(shù) " 在需要保持 某些數(shù)據(jù)或狀態(tài) 在 多次函數(shù)調(diào)用 之間不變的情況下非常有用 ,
例如 : 在 STL 算法中 , 函數(shù)對(duì)象經(jīng)常被用作 謂詞 或 用于在容器的每個(gè)元素上執(zhí)行某種操作的函數(shù) , 由于它們可以存儲(chǔ)狀態(tài) , 因此可以根據(jù)算法的需要進(jìn)行定制 ;
在下面的示例中 , 函數(shù)對(duì)象 中 維護(hù)了一個(gè)狀態(tài)位 , 用于記錄該 函數(shù)對(duì)象 的調(diào)用次數(shù) ;
下面的 函數(shù)對(duì)象 / 仿函數(shù) 中 , 存儲(chǔ)了狀態(tài) n , 每調(diào)用一次該仿函數(shù) , 該成員自增 1 ;
//函數(shù)對(duì)象 類重載了()
template <typename T>
class PrintT {
public:
void operator()(T& t) {
cout << n << " . " << t << endl;
// 每調(diào)用一次, 自增 1
n++;
}
private:
// 每調(diào)用一次, 該成員自增 1
// 該狀態(tài)一直存儲(chǔ)
int n = 0;
};
2、示例分析
在下面的代碼示例中 ,
首先 , 定義了 函數(shù)對(duì)象 / 仿函數(shù) PrintT 類 , 該類 重載了 函數(shù)調(diào)用操作符 () , 其重載函數(shù)是 void operator()(T& t)
;
- 在該 函數(shù)對(duì)象 中 , 存儲(chǔ)了一個(gè)狀態(tài)值 n ,
- 每次調(diào)用該 重載函數(shù) , 狀態(tài)值 n 都會(huì)自增 1 ;
//函數(shù)對(duì)象 類重載了()
template <typename T>
class PrintT {
public:
void operator()(T& t) {
cout << n << " . " << t << endl;
// 每調(diào)用一次, 自增 1
n++;
}
private:
// 每調(diào)用一次, 該成員自增 1
// 該狀態(tài)一直存儲(chǔ)
int n = 0;
};
然后 , 在 foreach 循環(huán)中 , 將該 函數(shù)對(duì)象 傳入 循環(huán)算法 中 , 每次遍歷 vector 容器中的元素時(shí) , 都會(huì)調(diào)用 該 函數(shù)對(duì)象 , 同時(shí) 每次調(diào)用 時(shí) , 函數(shù)對(duì)象中的 n 值都會(huì)自增 1 ;
// 向 foreach 循環(huán)中傳入函數(shù)對(duì)象
// 在函數(shù)對(duì)象中打印元素內(nèi)容
for_each(vec.begin(), vec.end(), PrintT<int>());
代碼示例 :
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
//函數(shù)對(duì)象 類重載了()
template <typename T>
class PrintT {
public:
void operator()(T& t) {
cout << n << " . " << t << endl;
// 每調(diào)用一次, 自增 1
n++;
}
private:
// 每調(diào)用一次, 該成員自增 1
// 該狀態(tài)一直存儲(chǔ)
int n = 0;
};
int main() {
// 創(chuàng)建一個(gè) vector 單端數(shù)組容器
vector<int> vec;
// 向容器中插入元素
vec.push_back(1);
vec.push_back(3);
vec.push_back(5);
// 向 foreach 循環(huán)中傳入函數(shù)對(duì)象
// 在函數(shù)對(duì)象中打印元素內(nèi)容
for_each(vec.begin(), vec.end(), PrintT<int>());
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
};
執(zhí)行結(jié)果 : 打印時(shí) , 先把狀態(tài)值 n 打印出來(lái) , 然后跟著打印 vector 容器中的元素 ,
0 . 1
1 . 3
2 . 5
請(qǐng)按任意鍵繼續(xù). . .
二、函數(shù)對(duì)象作為參數(shù)傳遞時(shí)值傳遞問題
1、for_each 算法的 函數(shù)對(duì)象 參數(shù)是值傳遞
下面開始分析 for_each 函數(shù)中 函數(shù)對(duì)象 作為參數(shù)的 具體細(xì)節(jié) ;
for_each 算法的調(diào)用代碼如下 :
// 向 foreach 循環(huán)中傳入函數(shù)對(duì)象
// 在函數(shù)對(duì)象中打印元素內(nèi)容
for_each(vec.begin(), vec.end(), PrintT<int>());
for_each 算法的函數(shù)原型如下 :
// FUNCTION TEMPLATE for_each
template <class _InIt, class _Fn>
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last)
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst) {
_Func(*_UFirst);
}
return _Func;
}
上述 for_each 函數(shù)的 形參 _Fn _Func 是一個(gè) 值 , 不是引用 ;
傳遞的是 引用 的話 , 那么 外部的對(duì)象 和 實(shí)參值 是相同的對(duì)象 ;
傳遞的是 值 的話 , 那么 實(shí)參 只是 外部的對(duì)象 的 副本值 , 在 for_each 函數(shù)中 , 無(wú)論如何操作改變實(shí)參 , 都不會(huì)影響到 外部的對(duì)象 ;
如果 在 for_each 算法中 調(diào)用了 函數(shù)對(duì)象 , 函數(shù)對(duì)象中 有 狀態(tài)改變 ;
在 for_each 算法 外部 繼續(xù)調(diào)用該 函數(shù)對(duì)象 , 由于 for_each 是 值傳遞 , 傳遞的 只是 函數(shù)對(duì)象副本 , 副本的 狀態(tài)改變 不會(huì)影響到外部函數(shù) ;
如果想要 保留上述 狀態(tài)改變 , 則需要使用 函數(shù)對(duì)象 接收 for_each 的返回值 , 這個(gè)函數(shù)對(duì)象 保留了 內(nèi)部 函數(shù)對(duì)象參數(shù)副本 的狀態(tài)值 ;
2、代碼示例 - for_each 函數(shù)的 函數(shù)對(duì)象 參數(shù)在外部不保留狀態(tài)
如果 在 for_each 算法中 調(diào)用了 函數(shù)對(duì)象 , 函數(shù)對(duì)象中 有 狀態(tài)改變 ;
在 for_each 算法 外部 繼續(xù)調(diào)用該 函數(shù)對(duì)象 , 由于 for_each 是 值傳遞 , 傳遞的 只是 函數(shù)對(duì)象副本 , 副本的 狀態(tài)改變 不會(huì)影響到外部函數(shù) ;
在外部調(diào)用 函數(shù)對(duì)象 時(shí) , 發(fā)現(xiàn)狀態(tài)值 還是 0 , 這說(shuō)明 值傳遞 改變的是 函數(shù)對(duì)象實(shí)參副本值 , 沒有影響外部的 函數(shù)對(duì)象 值 ;
0 . 666
代碼示例 :
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
//函數(shù)對(duì)象 類重載了()
template <typename T>
class PrintT {
public:
void operator()(T& t) {
cout << n << " . " << t << endl;
// 每調(diào)用一次, 自增 1
n++;
}
private:
// 每調(diào)用一次, 該成員自增 1
// 該狀態(tài)一直存儲(chǔ)
int n = 0;
};
int main() {
// 創(chuàng)建一個(gè) vector 單端數(shù)組容器
vector<int> vec;
// 向容器中插入元素
vec.push_back(1);
vec.push_back(3);
vec.push_back(5);
// 創(chuàng)建函數(shù)對(duì)象
PrintT<int> printT;
// 向 foreach 循環(huán)中傳入函數(shù)對(duì)象
// 在函數(shù)對(duì)象中打印元素內(nèi)容
for_each(vec.begin(), vec.end(), printT);
// 再次調(diào)用 函數(shù)對(duì)象
cout << "再次調(diào)用函數(shù)對(duì)象 : " << endl;
int a = 666;
printT(a);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
};
執(zhí)行結(jié)果 :
0 . 1
1 . 3
2 . 5
再次調(diào)用函數(shù)對(duì)象 :
0 . 666
請(qǐng)按任意鍵繼續(xù). . .
3、代碼示例 - for_each 函數(shù)的 函數(shù)對(duì)象 返回值
如果 在 for_each 算法中 調(diào)用了 函數(shù)對(duì)象 , 函數(shù)對(duì)象中 有 狀態(tài)改變 ;
在 for_each 算法 外部 繼續(xù)調(diào)用該 函數(shù)對(duì)象 , 由于 for_each 是 值傳遞 , 傳遞的 只是 函數(shù)對(duì)象副本 , 副本的 狀態(tài)改變 不會(huì)影響到外部函數(shù) ;
如果想要 保留上述 狀態(tài)改變 , 則需要使用 函數(shù)對(duì)象 接收 for_each 的返回值 , 這個(gè)函數(shù)對(duì)象 保留了 內(nèi)部 函數(shù)對(duì)象參數(shù)副本 的狀態(tài)值 ;
使用 PrintT<int> printT;
函數(shù)對(duì)象 變量 , 接收 for_each 算法的返回值 , 再次執(zhí)行該 函數(shù)對(duì)象 調(diào)用 , 發(fā)現(xiàn) 狀態(tài)值被保留了下來(lái) , 打印值為 :
3 . 666
代碼示例 :
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
//函數(shù)對(duì)象 類重載了()
template <typename T>
class PrintT {
public:
void operator()(T& t) {
cout << n << " . " << t << endl;
// 每調(diào)用一次, 自增 1
n++;
}
private:
// 每調(diào)用一次, 該成員自增 1
// 該狀態(tài)一直存儲(chǔ)
int n = 0;
};
int main() {
// 創(chuàng)建一個(gè) vector 單端數(shù)組容器
vector<int> vec;
// 向容器中插入元素
vec.push_back(1);
vec.push_back(3);
vec.push_back(5);
// 創(chuàng)建函數(shù)對(duì)象
PrintT<int> printT;
// 向 foreach 循環(huán)中傳入函數(shù)對(duì)象
// 在函數(shù)對(duì)象中打印元素內(nèi)容
printT = for_each(vec.begin(), vec.end(), printT);
// 再次調(diào)用 函數(shù)對(duì)象
cout << "再次調(diào)用函數(shù)對(duì)象 : " << endl;
int a = 666;
printT(a);
// 控制臺(tái)暫停 , 按任意鍵繼續(xù)向后執(zhí)行
system("pause");
return 0;
};
執(zhí)行結(jié)果 :文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-788503.html
0 . 1
1 . 3
2 . 5
再次調(diào)用函數(shù)對(duì)象 :
3 . 666
請(qǐng)按任意鍵繼續(xù). . .
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-788503.html
到了這里,關(guān)于【C++】STL 算法 ③ ( 函數(shù)對(duì)象中存儲(chǔ)狀態(tài) | 函數(shù)對(duì)象作為參數(shù)傳遞時(shí)值傳遞問題 | for_each 算法的 函數(shù)對(duì)象 參數(shù)是值傳遞 )的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!