[C++基礎]035_指標函數與函數指標

來源:互聯網
上載者:User

1. 前言

   關於指標函數和函數指標,特別是函數指標,相信很多C/C++ers跟我曾經一樣,對它抱有敬畏,認為它是很高深的東西,其實不然。要理解它花不了多少功夫,或許我一句話就能說清楚二者的區別,但是這樣也只是在腦子裡形成一個概念而已。大學時代,作為一名學生時,我可以一天看完毛概,考八九十分;但是我用了一個星期去看譚浩強的C++教材(儘管現在很多人鄙視這本教材),上機時卻仍無從下手,我可以侃侃而談,熟悉一切概念,但是就是編不出程式。這就是程式員的世界,凡事只有動手才能領悟真諦。不過這也應證了一句千古名句,也是我最喜歡的一句詩“紙上得來終覺淺,絕知此事要躬行”。

   本文所有代碼編譯及運行環境:windows 7 professionnal, Visual Studio2010 professional.

2. 概述

   按照行文的總-分-總的結構,這裡仍然先概括的介紹一下指標函數和函數指標的概念,然後再用程式來詳細的介紹二者。下面就是指標函數和函數指標的概念。

  【指標函數】:返回指標的函數。重點是它是一個函數,只是傳回值由普通的值或對象變成了指標,也就是說這個函數返回的是一塊記憶體的地址。

  【函數指標】:指向函數的指標。重點是它是一個指標,只是它指向的內容由普通的變數或對象變成了函數,也就是說它可以指向函數的入口地址。

3. 指標函數

   在介紹指標函數之前,我們先來看一個普通的函數。

 1 #include <iostream> 2 using namespace std; 3  4 class MyType{ 5 public: 6     MyType(int value):m_value(value){ 7         cout<<"Construct."<<endl; 8     } 9     ~MyType(){10         cout<<"Desconstruct."<<endl;11     }12 public:13     int m_value;14 };15 16 MyType getInstanceOfMyType(){17     MyType mt(10);18     cout<<&mt<<endl;19     return mt;20 }21 22 int main(){23 24     MyType mt = getInstanceOfMyType();25     cout<<&mt<<endl;26     cout<<mt.m_value<<endl;27 28     system("pause");29     return 0;30 }

   塗色部分就是我們需要注意的地方,函數"getInstanceOfMyType()"內部建立了一個MyType的對象,接著輸出了該對象的地址,最後返回了該對象。main函數裡面,通過調用該函數,獲得了函數的傳回值,接著列印了返回對象的地址,再輸出獲得對象的m_value屬性的值。輸出結果如下:

Construct.0045F688Desconstruct.0045F78810請按任意鍵繼續. . .

   可以看到,在"getInstanceOfMyType()"函數裡,對象建立之後又被銷毀了。從輸出可以看出,返回的對象地址與函數裡建立的對象地址是不一樣的,但是屬性m_value的值是一樣的,這說明通過該普通函數擷取的是函數內部建立對象的一個副本,這就是普通函數在返回對象時的處理。

   在看到普通函數的處理之後,我們再來看一個指標函數的處理,下面是一段指標函數的代碼,注意,這段代碼與上一段很相似,要注意區分。

 1 #include <iostream> 2 using namespace std; 3  4 class MyType{ 5 public: 6     MyType(int value):m_value(value){ 7         cout<<"Construct."<<endl; 8     } 9     ~MyType(){10         cout<<"Desconstruct."<<endl;11     }12 public:13     int m_value;14 };15 16 MyType *getInstanceOfMyType(){17     MyType *mt = new MyType(10);18     cout<<mt<<endl;19     return mt;20 }21 22 int main(){23 24     MyType *mt = getInstanceOfMyType();25     cout<<mt<<endl;26     cout<<mt->m_value<<endl;27 28     system("pause");29     return 0;30 }

   上面代碼著色的部分需要我們注意,特別是函數"getInstanceOfMyType()",它在這裡已經是一個指標函數了,那麼,這段程式的輸出是什麼呢?如下:

Construct.00754AA800754AA810請按任意鍵繼續. . .

   可以看出,在函數"getInstanceOfMyType()"中的對象一直沒有被調用解構函式,函數內和函數外的對象的地址是完全一樣的,當然,對象裡儲存的內容m_value的值也是一樣的。你可能會問,不是說函數調用完,就銷毀局部變數嗎?是的,它銷毀了,但是它只銷毀了"MyType *mt"這個指標,它指向的記憶體卻不會被銷毀。所以,在外面我們仍然可以繼續訪問這個對象。這種情況下,我們一般是需要在函數調用外面加上我們自己的delete操作的,上面的程式沒有添加這樣的操作,嚴格上來講是一個錯誤的程式。

   使用指標函數時,直接返回函數內部對象的地址,這樣就無需重新製造對象的副本,對效率的提升有協助。但是需要注意的是,一定要記得在函數外部將函數內部申請的記憶體釋放掉,否則就有記憶體溢出的風險。

4. 函數指標

   下面說道我們今天主要的話題了——函數指標。函數指標是一個很有用的技術,它使得我們可以通過指標就能執行某一個函數代碼。對於技術高超的人來說,它是一把【絕世好劍】,能夠解決很多問題。下面,我們就函數指標來探究一番。

   首先,來看一段最簡單的函數指標的代碼,注意聲明和調用的方式。

 1 #include <iostream> 2 using namespace std; 3  4 int printFunc(int value){ 5     cout<<"this is a print function. the value is:"<<value<<endl; 6     return 0; 7 } 8  9 int main(){10 11     int (*pFunction)(int x); // 這是一個函數指標變數12     pFunction = printFunc;   // 這裡將函數入口地址給函數指標13     (*pFunction)(7);         // 通過*運算子擷取了函數,再傳入參數7執行了函數14 15     system("pause");16     return 0;17 }

   上述代碼著色部分就是函數指標的聲明-定義-執行的過程,可以看出來,我只要將函數入口地址給函數指標就可以執行函數了。這裡有個知識點,就是關於函數的調用方式,一般我們調用函數的方式是這樣的:函數名(參數列表),但是其實函數的調用方式也可以這樣來寫:(*函數名)(參數列表)。即可以如下來調用函數,只是很少這樣用:

1 (*printFunc)(8);

   除此之外,我們還可以這樣寫:(&函數名)(參數列表)。即如下調用函數,這也幾乎沒人這樣用:

1 (&printFunc)(8);

   對於函數指標,它有兩個前提:①.就是指向的函數傳回值要與聲明的函數指標一致。②.指向的函數的參數類型及個數要與聲明的函數指標一致。否則,是無法編譯通過的。

5. 函數指標類型

   上面一節在使用函數指標的時候,直接聲明了一個函數指標。其實函數指標也可以藉助typedef聲明為一個類型,這樣我們就可以像定義int型變數一樣來定義一個函數指標了。定義函數指標類型代碼如下:

 1 #include <iostream> 2 using namespace std; 3  4 int printFunc(int value){ 5     cout<<"this is a print function. the value is:"<<value<<endl; 6     return 0; 7 } 8 typedef int (*PFunction)(int x); // 函數指標類型,注意傳回值和參數列表 9 10 int main(){11 12     PFunction ptrFunc; // 定義函數指標變數13     ptrFunc = printFunc;14     (*ptrFunc)(1); // 第一種調用方式15     ptrFunc(2);    // 第二種調用方式16 17     system("pause");18     return 0;19 }

6. 一個函數指標的妙用樣本

 1 #include <iostream> 2 using namespace std; 3  4 typedef void (*PFunction)(int x); // 函數指標類型,注意傳回值和參數列表 5  6 void printA(int value){ 7     cout<<"A - "<<value<<endl; 8 } 9 10 void printB(int value){11     cout<<"B - "<<value<<endl;12 }13 14 void printC(int value){15     cout<<"C - "<<value<<endl;16 }17 18 int main(){19     int choice;20     PFunction ptrFunc[3] = {printA, printB, printC};21     cin>>choice;22     ptrFunc[choice](choice);23 24     system("pause");25     return 0;26 }

   具體的這裡就不解說了,代碼很短,也很容易看懂。

7. 結語

   本文就指標函數和函數指標做了一個簡單的入門講解,希望讀者在閱讀完本文以後,對指標函數和函數指標有一個深入的認識。當然,寫作本文的目的也是為了強化筆者的C++基礎功底。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.