日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

一起來學習C++的函數指針和函數對象_C 語言

作者:itzyjr ? 更新時間: 2022-05-23 編程語言

函數指針

以下是庫中的一個排序數組的方法qsort()的函數原型。

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*, const void*));
  • base?-- 指向要排序的數組的第一個元素的指針。
  • num -- 由 base 指向的數組中元素的個數。
  • size?-- 數組中每個元素的大小,以字節為單位。
  • compar?-- 用來比較兩個元素的函數。

對于可以使用常規關系運算符進行比較的類型,常規比較函數可能如下所示:

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 
#include 
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 menu choice:
u) uppercase l) lowercase
t) transposed case o) original case
n) next string
Please enter u, l, t, o, or n:
|u
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
abc
#include 
#include 
#include 
#include 
#include 
#define LEN 81
char showmenu();
void show(void (* fp)(char*), char* str);
void ToUpper(char*); // 把字符串轉換為大寫
void ToLower(char*); // 把字符串轉換為小寫
void Transpose(char*); // 大小寫轉置
void Dummy(char*); // 不更改字符串
using namespace std;
int main() {
	char line[LEN];
	char copy[LEN];
	char choice;
	void (* pfun)(char*); // 聲明一個函數指針, 被指向的函數接受char *類型的參數, 無返回值
	cout << "Enter a string (empty line to quit):";
	while (cin >> line) {
		while ((choice = showmenu()) != 'n') {
			switch (choice) { // switch語句設置指針
			case 'u':
				pfun = ToUpper;
				break;
			case 'l':
				pfun = ToLower;
				break;
			case 't':
				pfun = Transpose;
				break;
			case 'o':
				pfun = Dummy;
				break;
			}
			strcpy(copy, line); // 為show()函數拷貝一份
			show(pfun, copy); // 根據用戶的選擇, 使用選定的函數
		}
		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); // 轉換為小寫
	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); // 把用戶選定的函數作用于str
	cout << str << endl; // 顯示結果
}
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) {
} //不改變字符串

函數對象

函數對象是專門設計用于語法與函數相似的對象。在C++中,這是通過在類中定義成員函數operator()來實現的,例如:

struct myclass {
	int operator()(int a) {
		return a;
	}
} myobject;
 
int x = myobject(0);

它們通常用作函數的參數,例如傳遞給標準算法的謂詞或比較函數。

標準庫預先定義了些function object。所謂function object,是某種class的實例對象,這類class對function call運算符做了重載操作,如此一來可使function object被當成一般函數來使用。

function object實現了我們原本可能以獨立函數加以定義的事物。但又何必如此呢?
主要是為了效率。我們可以令call運算符成為inline,從而消除“通過函數指針來調用函數”時需要付出的額外代價。

標準庫事先定義了一組function object,分為:

算術運算(arithmetic)、關系運算(relational)和邏輯運算(logical)三大類。

以下列表中的type在實際使用時會替換為內置類型或class類型:

6個算術運算

plus,minus,negate

multiplies,divides,modules

6個關系運算

less,less_equal,greater

greater_equal,equal_to,not_equal_to

3個邏輯運算 logical_and,logical_or,logic_not

要使用事先定義的function object,首先得包含相關頭文件:<functional>

默認情況下sort()是升序排列,我們將元素降序排列:

sort(vec.begin(), vec.end(), greater());

其中的greater()會產生一個未命名的class template object,傳給sort()。

binary_search()期望其搜索對象先經過排序,為了正確搜索vector,就必須傳給它某個function object object,供vector排序使用:

binary_search(vec.begin(), vec.end(), elem, greater());

我們對Fibonacci數列可以做些其他操作,如:每個元素和自身相加、和自身相乘、被加到對應的Pell數列等等。做法之一是使用泛型算法transform()并搭配plus和multiplies

我們必須傳給transform()的參數有:

?一對iterator,標示出欲轉換的元素范圍;

?一個iterator,所指元素將應用于轉換上,元素范圍同?;

?一個iterator,所指位置(及其后面的空間)用來存放轉換結果;

?一個function object,表現出我們想要應用的轉換操作。

以下是將Pell數列加到Fibonacci數列的寫法:

transform(fib.begin(), fib.end(), //?
          pell.begin(),           //?
          fib_plus_pell.begin(),  //?
          plus);             //?

transform()的定義:

function template std::transform

unary operation(1)	
template 
OutputIterator transform(InputIterator first1, InputIterator last1,
                         OutputIterator result, UnaryOperation op);
binary operation(2)	
template 
OutputIterator transform(InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, OutputIterator result,
                         BinaryOperation binary_op);
————————————————————————————————————————————————————
將操作順序應用于一(1)或兩(2)個范圍的元素,并將結果存儲在從結果開始的范圍中。
(1) 一元操作
將op應用于[first1,last1]范圍內的每個元素,并將每個操作返回的值存儲在從result開始的范圍內。
(2) 二元操作
使用范圍[first1,last1]中的每個元素作為第一個參數,并使用范圍中從first2開始的各個參數作為
第二個參數來調用binary_op。每個調用返回的值存儲在從result開始的范圍中。
 
該函數允許目標范圍與其中一個輸入范圍相同,以便進行適當的轉換。

函數對象適配器:

function object less期望外界傳入兩個值,如果第一個值小于第二個值就返回true。本例中,每個元素都必須和用戶所指定的數值進行比較。理想情形下,我們需要將less轉化為一個一元(unary)運算符。這可通過“將其第二個參數綁定(bind)至用戶指定的數值”完成。這么一來less便會將每個元素拿出來一一與用戶指定的數值比較。

真的可以做到這樣嗎?是的。標準庫提供adapter(適配器)便應此而生。

function object adapter會對function object進行修改操作。binder adapter(綁定適配器)會將function object的參數綁定至某特定值,使binary(二元) function object轉化為unary(一元)function object。這正是我們需要的。

標準庫提供了兩個binder adapter

bind1st會將指定值綁定至第一操作數;

bind2nd將指定值綁定至第二操作數。

如:a < b,則a是第一操作數,b是第二操作數。

vector filter &vec, int val, less <) {
	vector nvec;
	vector::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的第二個參數身上。于是,less會將每個元素拿來和val比較。上例第一操作數是*iter,第二操作數就是固定值val。如果*iter

find_if()的定義如下:

template 
InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred);
●first、last:輸入迭代器到序列的初始和最終位置。使用的范圍是[first,last),它包含first和last之間的所有元素,包括first指向的元素,但不包括last指向的元素。
●pred:接受范圍內的元素作為參數并返回可轉換為bool類型的值的【一元函數】。返回的值表明該元素是否被認為是此函數的上下文中的匹配。 函數不能修改它的參數。 它可以是函數指針,也可以是函數對象(function object)。
●返回值:指向pred不返回false的范圍內第一個元素的迭代器。 如果pred對所有元素都為false,則函數返回last。
這個函數模板的行為相當于:
template
InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred) {
  while (first!=last) {
    if (pred(*first)) return first;
    ++first;
  }
  return last;
}

下面看一個泛型函數find_if()的例子:

#include      // std::cout
#include     // std::find_if
#include        // std::vector
bool IsOdd (int i) {
  return ((i%2)==1);
}
int main () {
  std::vector myvector;
  myvector.push_back(10);
  myvector.push_back(25);
  myvector.push_back(40);
  myvector.push_back(55);
  std::vector::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 
#include 
#include 
using namespace std;
int main () {
	int numbers[] = {10,-20,-30,40,-50};
	int cx = count_if(numbers, numbers+5, bind2nd(less(), 0));
	cout << "There are " << cx << " negative elements.\n";
	return 0;
}
There are 3 negative elements.
#include 
#include 
#include 
using namespace std;
int main () {
	int numbers[] = {10,-20,-30,40,-50};
	int cx = count_if(numbers, numbers+5, bind1st(less(), 0));
	cout << "There are " << cx << " positive elements.\n";
	return 0;
}
There are 2 positive elements.

總結

原文鏈接:https://blog.csdn.net/itzyjr/article/details/123618936

欄目分類
最近更新