一起來學習C++的函數(shù)指針和函數(shù)對象
函數(shù)指針
以下是<cstdlib>庫中的一個排序數(shù)組的方法qsort()的函數(shù)原型。
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*, const void*));base-- 指向要排序的數(shù)組的第一個元素的指針。num-- 由 base 指向的數(shù)組中元素的個數(shù)。size-- 數(shù)組中每個元素的大小,以字節(jié)為單位。compar-- 用來比較兩個元素的函數(shù)。
對于可以使用常規(guī)關(guān)系運算符進行比較的類型,常規(guī)比較函數(shù)可能如下所示:
int compareMyType (const void * a, const void * b) {
if ( *(MyType*)a < *(MyType*)b ) return -1;
if ( *(MyType*)a == *(MyType*)b ) return 0;
if ( *(MyType*)a > *(MyType*)b ) return 1;
}#include <cstdlib>
#include <iostream>
int cmpfunc (const void* a, const void* b);
using namespace std;
int main() {
int values[] = { 88, 56, 100, 2, 25 };
qsort(values, sizeof(values)/sizeof(int), sizeof(int), cmpfunc);
cout << "排序之后的列表:" << endl;
for(int n = 0 ; n < 5; n++ ) {
cout << values[n] << " ";
}
return 0;
}
int cmpfunc (const void* a, const void* b) {
return ( *(int*)a - *(int*)b );
}Enter a string (empty line to quit):|abc<Enter> Enter menu choice: u) uppercase l) lowercase t) transposed case o) original case n) next string Please enter u, l, t, o, or n: |u<Enter> ABC Enter menu choice: u) uppercase l) lowercase t) transposed case o) original case n) next string Please enter u, l, t, o, or n: |l<Enter> abc
#include <cstdio>
#include <cstring>
#include <string>
#include <cctype>
#include <iostream>
#define LEN 81
char showmenu();
void show(void (* fp)(char*), char* str);
void ToUpper(char*); // 把字符串轉(zhuǎn)換為大寫
void ToLower(char*); // 把字符串轉(zhuǎn)換為小寫
void Transpose(char*); // 大小寫轉(zhuǎn)置
void Dummy(char*); // 不更改字符串
using namespace std;
int main() {
char line[LEN];
char copy[LEN];
char choice;
void (* pfun)(char*); // 聲明一個函數(shù)指針, 被指向的函數(shù)接受char *類型的參數(shù), 無返回值
cout << "Enter a string (empty line to quit):";
while (cin >> line) {
while ((choice = showmenu()) != 'n') {
switch (choice) { // switch語句設(shè)置指針
case 'u':
pfun = ToUpper;
break;
case 'l':
pfun = ToLower;
break;
case 't':
pfun = Transpose;
break;
case 'o':
pfun = Dummy;
break;
}
strcpy(copy, line); // 為show()函數(shù)拷貝一份
show(pfun, copy); // 根據(jù)用戶的選擇, 使用選定的函數(shù)
}
cout << "Enter a string (empty line to quit):";
}
cout << "Bye!";
return 0;
}
char showmenu() {
char ans;
cout << "Enter menu choice:" << endl;
cout << "u) uppercase l) lowercase" << endl;
cout << "t) transposed case o) original case" << endl;
cout << "n) next string" << endl;
ans = getchar(); // 獲取用戶的輸入
ans = tolower(ans); // 轉(zhuǎn)換為小寫
while (strchr("ulton", ans) == NULL) {
cout << "Please enter u, l, t, o, or n:" << endl;
ans = tolower(getchar());
}
return ans;
}
void show(void (* fp)(char*), char* str) {
(*fp)(str); // 把用戶選定的函數(shù)作用于str
cout << str << endl; // 顯示結(jié)果
}
void ToUpper(char* str) {
while (*str) {
*str = toupper(*str);
str++;
}
}
void ToLower(char* str) {
while (*str) {
*str = tolower(*str);
str++;
}
}
void Transpose(char* str) {
while (*str) {
if (islower(*str))
*str = toupper(*str);
else if (isupper(*str))
*str = tolower(*str);
str++;
}
}
void Dummy(char* str) {
} //不改變字符串函數(shù)對象
函數(shù)對象是專門設(shè)計用于語法與函數(shù)相似的對象。在C++中,這是通過在類中定義成員函數(shù)operator()來實現(xiàn)的,例如:
struct myclass {
int operator()(int a) {
return a;
}
} myobject;
int x = myobject(0);它們通常用作函數(shù)的參數(shù),例如傳遞給標準算法的謂詞或比較函數(shù)。
標準庫預(yù)先定義了些function object。所謂function object,是某種class的實例對象,這類class對function call運算符做了重載操作,如此一來可使function object被當成一般函數(shù)來使用。
function object實現(xiàn)了我們原本可能以獨立函數(shù)加以定義的事物。但又何必如此呢?
主要是為了效率。我們可以令call運算符成為inline,從而消除“通過函數(shù)指針來調(diào)用函數(shù)”時需要付出的額外代價。
標準庫事先定義了一組function object,分為:
算術(shù)運算(arithmetic)、關(guān)系運算(relational)和邏輯運算(logical)三大類。
以下列表中的type在實際使用時會替換為內(nèi)置類型或class類型:
| 6個算術(shù)運算 | plus<type>,minus<type>,negate<type>, multiplies<type>,divides<type>,modules<type> |
| 6個關(guān)系運算 | less<type>,less_equal<type>,greater<type>, greater_equal<type>,equal_to<type>,not_equal_to<type> |
| 3個邏輯運算 | logical_and<type>,logical_or<type>,logic_not<type> |
要使用事先定義的function object,首先得包含相關(guān)頭文件:<functional>
默認情況下sort()是升序排列,我們將元素降序排列:
sort(vec.begin(), vec.end(), greater<int>());
其中的greater<int>()會產(chǎn)生一個未命名的class template object,傳給sort()。
binary_search()期望其搜索對象先經(jīng)過排序,為了正確搜索vector,就必須傳給它某個function object object,供vector排序使用:
binary_search(vec.begin(), vec.end(), elem, greater<int>());
我們對Fibonacci數(shù)列可以做些其他操作,如:每個元素和自身相加、和自身相乘、被加到對應(yīng)的Pell數(shù)列等等。做法之一是使用泛型算法transform()并搭配plus<int>和multiplies<int>。
我們必須傳給transform()的參數(shù)有:
?一對iterator,標示出欲轉(zhuǎn)換的元素范圍;
?一個iterator,所指元素將應(yīng)用于轉(zhuǎn)換上,元素范圍同?;
?一個iterator,所指位置(及其后面的空間)用來存放轉(zhuǎn)換結(jié)果;
?一個function object,表現(xiàn)出我們想要應(yīng)用的轉(zhuǎn)換操作。
以下是將Pell數(shù)列加到Fibonacci數(shù)列的寫法:
transform(fib.begin(), fib.end(), //?
pell.begin(), //?
fib_plus_pell.begin(), //?
plus<int>); //?transform()的定義:
function template <algorithm> std::transform
unary operation(1)
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1,
OutputIterator result, UnaryOperation op);
binary operation(2)
template <class InputIterator1, class InputIterator2,
class OutputIterator, class BinaryOperation>
OutputIterator transform(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, OutputIterator result,
BinaryOperation binary_op);
————————————————————————————————————————————————————
將操作順序應(yīng)用于一(1)或兩(2)個范圍的元素,并將結(jié)果存儲在從結(jié)果開始的范圍中。
(1) 一元操作
將op應(yīng)用于[first1,last1]范圍內(nèi)的每個元素,并將每個操作返回的值存儲在從result開始的范圍內(nèi)。
(2) 二元操作
使用范圍[first1,last1]中的每個元素作為第一個參數(shù),并使用范圍中從first2開始的各個參數(shù)作為
第二個參數(shù)來調(diào)用binary_op。每個調(diào)用返回的值存儲在從result開始的范圍中。
該函數(shù)允許目標范圍與其中一個輸入范圍相同,以便進行適當?shù)霓D(zhuǎn)換。函數(shù)對象適配器:
function object less<type>期望外界傳入兩個值,如果第一個值小于第二個值就返回true。本例中,每個元素都必須和用戶所指定的數(shù)值進行比較。理想情形下,我們需要將less<type>轉(zhuǎn)化為一個一元(unary)運算符。這可通過“將其第二個參數(shù)綁定(bind)至用戶指定的數(shù)值”完成。這么一來less<type>便會將每個元素拿出來一一與用戶指定的數(shù)值比較。
真的可以做到這樣嗎?是的。標準庫提供adapter(適配器)便應(yīng)此而生。
function object adapter會對function object進行修改操作。binder adapter(綁定適配器)會將function object的參數(shù)綁定至某特定值,使binary(二元) function object轉(zhuǎn)化為unary(一元)function object。這正是我們需要的。
標準庫提供了兩個binder adapter:
bind1st會將指定值綁定至第一操作數(shù);
bind2nd將指定值綁定至第二操作數(shù)。
如:a < b,則a是第一操作數(shù),b是第二操作數(shù)。
vector<int> filter<const vector<int> &vec, int val, less<int> <) {
vector<int> nvec;
vector<int>::const_iterator iter = vec.begin();
while ((iter = find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end()) {
nvec.push_back(*iter);
iter++;
}
return nvec;
}bind2nd(less, val);會把val綁定于less<int>的第二個參數(shù)身上。于是,less<int>會將每個元素拿來和val比較。上例第一操作數(shù)是*iter,第二操作數(shù)就是固定值val。如果*iter<val則true。
find_if()的定義如下:
template <class InputIterator, class UnaryPredicate>
InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred);
●first、last:輸入迭代器到序列的初始和最終位置。使用的范圍是[first,last),它包含first和last之間的所有元素,包括first指向的元素,但不包括last指向的元素。
●pred:接受范圍內(nèi)的元素作為參數(shù)并返回可轉(zhuǎn)換為bool類型的值的【一元函數(shù)】。返回的值表明該元素是否被認為是此函數(shù)的上下文中的匹配。 函數(shù)不能修改它的參數(shù)。 它可以是函數(shù)指針,也可以是函數(shù)對象(function object)。
●返回值:指向pred不返回false的范圍內(nèi)第一個元素的迭代器。 如果pred對所有元素都為false,則函數(shù)返回last。
這個函數(shù)模板的行為相當于:
template<class InputIterator, class UnaryPredicate>
InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred) {
while (first!=last) {
if (pred(*first)) return first;
++first;
}
return last;
}下面看一個泛型函數(shù)find_if()的例子:
#include <iostream> // std::cout
#include <algorithm> // std::find_if
#include <vector> // std::vector
bool IsOdd (int i) {
return ((i%2)==1);
}
int main () {
std::vector<int> myvector;
myvector.push_back(10);
myvector.push_back(25);
myvector.push_back(40);
myvector.push_back(55);
std::vector<int>::iterator it = std::find_if(myvector.begin(), myvector.end(), IsOdd);
std::cout << "The first odd value is " << *it << '\n';
return 0;
}The first odd value is 25
看一個bind2nd()和bind1st()的例子:
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main () {
int numbers[] = {10,-20,-30,40,-50};
int cx = count_if(numbers, numbers+5, bind2nd(less<int>(), 0));
cout << "There are " << cx << " negative elements.\n";
return 0;
}There are 3 negative elements.
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main () {
int numbers[] = {10,-20,-30,40,-50};
int cx = count_if(numbers, numbers+5, bind1st(less<int>(), 0));
cout << "There are " << cx << " positive elements.\n";
return 0;
}There are 2 positive elements.
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
數(shù)據(jù)結(jié)構(gòu)之數(shù)組Array實例詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之數(shù)組Array實例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
探討:用兩個棧實現(xiàn)一個隊列(我作為面試官的小結(jié))
作為面試官的我,經(jīng)常拿這道用兩個棧實現(xiàn)一個隊列的面試題來考面試者,通過對面試者的表現(xiàn)和反應(yīng),有一些統(tǒng)計和感受,在此做個小結(jié)2013-05-05
淺談C語言中strcpy,strcmp,strlen,strcat函數(shù)原型
下面小編就為大家?guī)硪黄獪\談C語言中strcpy,strcmp,strlen,strcat函數(shù)原型。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04

