📄 functionpointer.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>函式指标</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">C++
Gossip: 函式指标</a></h1>
程式在执行时,函式本身在记忆体中也占有一个空间,而函式名称本身也就是指向该空间位址的参考名称,当呼叫函式名称时,程式就会去执行该函式名称所指向的
记忆体空间中之指令。 <br>
<br>
您可以宣告函式指标,并让它与某个函式指向相同的空间,函式指标的宣告方式如下所示: <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">传回值型态
(*指标名称)(传递参数); </span><br>
</div>
<br>
一个函式型态由传回值型态与参数列决定,不包括函式名称,一个函式指标可指向具有相同型态的函式,也就是具有相同传回值型态和参数列的函式。<br>
<br>
下面这个程式是个简单的示范,它以函式指标ptr来取得函式foo()的位址,使用它来呼叫函式,将与使用foo()来呼叫函式具有相同的作用,程式以整
数方式显示两个的记忆体空间是相同的: <br>
<br>
<pre>#include <iostream> <br>using namespace std; <br><br>int foo(); <br><br>int main() { <br> int (*ptr)() = 0; <br><br> ptr = foo; <br><br> foo(); <br> ptr(); <br><br> cout << "address of foo:" <br> << (int)foo << endl; <br> cout << "address of foo:" <br> << (int)ptr << endl; <br><br> return 0; <br>} <br><br>int foo() { <br> cout << "function point" << endl; <br><br> return 0; <br>}</pre>
<span class="postbody"><br>
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">function point<br>
function point<br>
address of foo:4199502<br>
address of foo:4199502</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
如果函式带有参数,则函式指标本身的宣告也必须指定相同的参数型态与个数,下面这个程式用来显示重载函式会分别占据不同的记忆体空间: <br>
<br>
<pre>#include <iostream> <br>using namespace std; <br><br>int foo(int, int); <br>char foo(int, char); <br><br>int main() { <br> int (*ptr1)(int, int) = 0; <br> char (*ptr2)(int, char) = 0; <br><br> ptr1 = foo; // get address of foo(int, int) <br> ptr2 = foo; // get address of foo(int, char) <br><br> ptr1(1, 2); <br> ptr2(3, 'c'); <br><br> cout << "address of foo(int, int): " <br> << (int)ptr1 << endl; <br> cout << "address of foo(int, char): " <br> << (int)ptr2 << endl; <br><br> return 0; <br>} <br><br>int foo(int n1, int n2) { <br> cout << "foo(int, int): " <br> << n1 << "\t" << n2 <br> << endl;<br><br> return 0; <br>} <br><br>char foo(int n, char c) { <br> cout << "foo(int, char): " <br> << n << "\t" << c <br> << endl;<br><br> return c; <br>}</pre>
<span class="postbody"><br>
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">foo(int, int):
1 2<br>
foo(int, char): 3 c<br>
address of foo(int, int): 4199548<br>
address of foo(int, char): 4199648</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
由于在宣告函式指标时已指定了参数列的资料型态与个数,所以虽然在指定ptr1与ptr2时都使用foo函式名称,但程式仍可以自动判别出我们是要指定哪
个过载函式的位址。 <br>
<br>
来看看一个应用的例子,假设您要撰写一个排序sort()函式,您希望排序时可以由大至小,也可以由小至大,比较简单的作法是在sort()上加上一个额
外的参数,可以传入常数或列举,例如如果指定1的话就由大至小,指定0的话就由小至大,这需要在函式中加上额外的判断,为了简化sort()的撰写,可以
传入一个函式位址,函式中就无需额外的判断,例如:<br>
<ul>
<li>sort.h</li>
</ul>
<pre>void swap(int&, int&);<br>bool larger(int a, int b);<br>bool smaller(int a, int b);<br>void sort(int*, int, bool (*compare)(int, int));</pre>
<br>
<ul>
<li>sort.cpp</li>
</ul>
<pre>#include "sort.h";<br><br>void swap(int &a, int &b) {<br> int t = a; <br> a = b; <br> b = t;<br>}<br><br>bool larger(int a, int b) {<br> return a > b;<br>}<br><br>bool smaller(int a, int b) {<br> return a < b;<br>}<br><br>void sort(int* arr, int length, bool (*compare)(int, int)) { <br> int flag = 1; <br><br> for(int i = 0; i < length-1 && flag == 1; i++) { <br> flag = 0; <br> for(int j = 0; j < length-i-1; j++) { <br> if(compare(arr[j+1], arr[j])) { <br> swap(arr[j+1], arr[j]); <br> flag = 1; <br> } <br> } <br> } <br>}</pre>
<br>
<ul>
<li>main.cpp</li>
</ul>
<pre>#include <iostream> <br>#include "sort.h"<br>using namespace std; <br><br>int main() { <br> int number1[] = {3, 5, 1, 6, 9};<br> sort(number1, 5, larger);<br> cout << "大的在前 ";<br> for(int i = 0; i < 5; i++) {<br> cout << number1[i] << " ";<br> }<br> cout << endl;<br><br> int number2[] = {3, 5, 1, 6, 9};<br> sort(number2, 5, smaller);<br> cout << "小的在前 ";<br> for(int i = 0; i < 5; i++) {<br> cout << number2[i] << " ";<br> }<br> cout << endl;<br> <br> return 0; <br>}</pre>
<br>
<span class="postbody">
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">大的在前 9 6 5 3 1<br>
小的在前 1 3 5 6 9</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
在函式中,不必理会传入的实际函式,只要呼叫compare()就可以了,在这个例子中,您的sort()上的函式指标宣告有些难以阅读,您可以使用
typedef,定义一个比较容易阅读的名称,例如:<br>
<ul>
<li>sort.h</li>
</ul>
<pre>typedef bool (*CMP)(int, int);<br>void swap(int&, int&);<br>bool larger(int a, int b);<br>bool smaller(int a, int b);<br>void sort(int*, int, CMP);</pre>
<br>
<ul>
<li>sort.cpp</li>
</ul>
<pre>#include "sort.h"<br><br>void swap(int &a, int &b) {<br> int t = a; <br> a = b; <br> b = t;<br>}<br><br>bool larger(int a, int b) {<br> return a > b;<br>}<br><br>bool smaller(int a, int b) {<br> return a < b;<br>}<br><br>void sort(int* arr, int length, CMP compare) { <br> int flag = 1; <br><br> for(int i = 0; i < length-1 && flag == 1; i++) { <br> flag = 0; <br> for(int j = 0; j < length-i-1; j++) { <br> if(compare(arr[j+1], arr[j])) { <br> swap(arr[j+1], arr[j]); <br> flag = 1; <br> } <br> } <br> } <br>}</pre>
<br>
可以看到,重新使用typedef定义CMP名称后,函式比较容易阅读的多了。<br>
<br>
您也可以宣告函式指标阵列,例如:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">bool
(*compare[10])(int, int);</span><br>
</div>
<br>
上面这个宣告产生具有10个元素的阵列,可以储存10个sort函式型态的位址,不过这样的宣告实在难以阅读,可以使用typedef来改进:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">typedef bool
(*CMP)(int, int);</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">CMP compare[10];</span><br>
</div>
<br>
可以看到这次的宣告比较容易阅读了。<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -