第六章C++:函數基礎與應用

來源:互聯網
上載者:User

第六章 函數

函數是一個命名了的代碼塊,通過調用函數執行相應的代碼。

函數基礎

  • 通過調用運算子(call operator)來執行函數。其形式是一對圓括弧。

  • 函數的調用完成兩項工作(如下),此時主調函數(calling function)的執行被暫時中斷,被調函數(called function)開始執行。

    • 用實參初始化函數對應的形參。

    • 將控制權轉移給被調函數。

  • return語句:

    • 返回return語句中的值

    • 將控制權從被調函數移回主調函數

局部對象

  • 名字有範圍,對象有生命週期(lifetime)

  • 自動對象(automatic object):當函數的控制路徑經過變數定義語句時建立該對象,當達到定義所在的塊末尾時銷毀它。

  • 局部靜態對象:程式執行路徑第一次經過對象定義語句時初始化,知道程式終止才被銷毀。

    • 將局部變數定義為static獲得,例如:

      //統計函數count_calls ()被調用了多少次
      size_t count_calls ()
      {
      static size_t ctr = 0; //調用結束後,這個值仍然有效
      return ++ctr;
      }
      int main()
      {
      for (size_t i = 0; i != 10; ++i)
      cout << cout_calls() << endl;
      return 0;
      }

函式宣告

  • 也稱作函數原型(function prototype)

  • 函數三要素(傳回型別、函數名、形參類型)描述了函數的介面,函式宣告中形參名可省略。

  • 函數應在標頭檔中聲明,源檔案中定義。

  • 分離式編譯

參數傳遞

如果形參是參考型別,它將綁定到對應的實參上;否則,將實參的值拷貝後賦給形參。
- 如果無需修改引用形參的值,最好將其聲明為常量引用。

main:處理命令列選項

假設main函數位於可執行檔prog內,我們可以向程式傳遞下面的選項:

prog -d -o ofile data0

這些命令通過兩個可選的形參傳遞給main函數:

int main(int argc, char *argv[]) {...}//或:int main(int argc, char **argv) {...}

當實參傳給main函數之後,argv的第一個元素指向程式的名字或者一個Null 字元串,接下來的元素一次傳遞命令列提供的實參。最後一個指標只會掉元素值保證為0。
- 以上面的命令列為例:

argc = 5;argv[0] = "prog";argv[1] = "-d";argv[2] = "-o";argv[3] = "ofile";argv[4] = "data0";argv[5] = 0;

含有可變形參的函數

  • C++11新標準提供兩種方法編寫能處理不同數量實參的函數:

    1. 所有實參類型相同,可以傳遞一個名為initializer_list的標準庫類型。

    2. 實參類型不同,我們可以編寫一種特殊的函數,叫做可變參數模板。

  • C++還有一種特殊的形參類型:省略符。可以用它傳遞可變數量的實參。這種功能一般只用於與C函數互動的介面程式。

  • initializer_list形參

    • 其類型定義在同名的標頭檔中

    • 提供如下操作:

      initializer_list<T> lst; //預設初始化,T類型元素的空列表
      initializer_list<T> lst{a,b,c...};
      //lst的元素數量和初始值一樣多;lst的元素是對應初始值的副本;列表中的元素是const
      lst2(lst)
      lst2 = lst //拷貝或複製一個initializer_list對象不會拷貝列表中的元素;拷貝後,原始列表和副本元素共用
      lst.size() //列表中元素的數量
      lst.begin() //返回指向lst中首元素的指標
      lst.end() //返回指向lst中尾元素下一位置的指標

傳回型別和return語句

  • 引用返回左值,其他傳回型別得到右值。

  • 列表初始化傳回值:C++11新標準規定,函數可以返回花括弧包圍的值的列表。

主函數main的傳回值

  • 允許main函數沒有傳回值(若沒有,編譯器隱式地插入return 0)

  • 返回0表示執行成功,其他值依機器而定。

  • 為了使傳回值與機器無關,cstdlib標頭檔定義了兩個預先處理變數,分別表示成功和失敗:

    return EXIT_FAILURE;
    return EXIT_SUCCESS;
    //因為它們是預先處理變數,所以既不能在前面加上std::,也不能在using聲明裡出現。

返回數組指標

  1. 使用類型別名

    typedef int arrT[10]; //arrT是一個類型別名,它表示的類型是含有10個整數的數組
    using arrT = int[10]; //與上一句等價
    arrT* func(int i); //func返回一個指向含有10個整數的數組的指標

  2. 聲明一個返回數組指標的函數,形式如下

    Type (*function(parameter_list)) [dimension]
    //Type表示返回的數組指標指向的數組元素類型
    //dimension表示數組的大小
    //例如:
    int (*func(int i)) [10];

  3. 使用尾置傳回型別(C++11)

    auto func(int i) -> int(*)[10];

  4. 使用decltype

    int odd[] = {1,3,5,7,9};
    int even[] = {0,2,4,6,8};
    decltype(odd) *arrPtr(int i)
    {
    return (i % 2) ? &odd : &even; //返回一個指向數組的指標
    }

函數重載

如果同一範圍內的幾個函數名字相同但形參列表不同,我們稱之為重載(overloaded)函數

  • 不允許兩個函數除了傳回型別外其他所有要素都相同。

  • 重載與範圍:一旦在當前範圍中找到了所需的名字,編譯器就會忽略掉外層範圍中的同名實體。

特殊用途語言特性

介紹三種函數相關的語言特性:預設實參、內嵌函式、constexpr函數。

預設實參

  • 調用包含預設實參的函數時,可以包含該實參,也可以省略該實參。

  • 一旦某個形參被賦予了預設值,它後面所有的形參都必須有預設值。

內嵌函式(inline)

調用函數一般比求等價運算式的值要慢,內嵌函式可避免函數調用的開銷。
- 將函數指定為內嵌函式,通常就是將它在每個調用點上“內聯地”展開。

constexpr函數

  • 函數的傳回型別和所有的形參類型都得是字面實值型別。

  • 函數中必須有且只有一條return語句。

  • constexpr函數被隱式地指定為內嵌函式。

內嵌函式和constexpr函數通常定義在標頭檔中

調試協助

程式可以包含一些用於調試的代碼,但這些代碼只在開發程式時使用。當應用程式編寫完成準備發布時,要先屏蔽掉調試代碼。這種方法用到兩項預先處理功能:assert和NDEBUG。

assert預先處理宏

#include <cassert>assert(expr);//首先對expr求值,//如果運算式為假(即0),assert輸出資訊並終止程式的執行。//如果運算式為真(即非0),assert什麼也不做。//例如:對一個文本進行操作的程式可能要求所給定單詞的長度都大於某個閾值。assert(word.size() > threshold;

NDEBUG預先處理變數

  • assert的行為依賴於一個名為NDEBUG的預先處理變數的狀態。如果定義了NDEBUG,則assert什麼也不做。預設狀態下沒有定義NDEBUG,此時assert將運行執行時檢查。

    • 使用#define語句定義NDEBUG,從而關閉調試狀態。

    • 很多編譯器都提供了命令列選項使我們可以定義預先處理變數。

      $ CC -D NDEBUG main.C #微軟編譯器中用 /D

  • 這隻是偵錯工具的輔助手段,不能代替真正的邏輯檢查,也不能代替程式本應該包含的錯誤檢查。

  • 除了assert以外,也能使用NDEBUG編寫自己的條件調試代碼:

//如果定義了NDEBUG,#ifndef和#endif之間的代碼將被忽略void print(const int ia[], aize_t size){    #ifndef NDEBUG        //_ _func_ _是編譯器定義的一個局部靜態變數,用於存放函數的名字,它是const char的一個靜態數組。        cerr << _ _func_ _ << "array size is " << size << endl;    #endif}

除了_ _ func _ _之外,還有其它四個名字:

_ _FILE_ _ 存放檔案名稱的字串字面值_ _LINE_ _ 存放當前行號的整型字面值_ _TIME_ _ 存放檔案編譯時間的字串字面值_ _DATA_ _ 存放檔案編譯日期的字串字面值

函數指標

bool lengthCompare(const string &, const string &);//pf指向一個函數,該函數的參數是兩個const string的引用,傳回值是bool類型。注意圓括弧必不可少bool (*pf) (const string &, const string &);    //未初始化

當我們把函數名作為值使用時,該函數自動地轉換成指標

pf = lengthCompare;     //pf指向名為lengthCompare的函數pf = &lengthCompare;    //等價指派陳述式,&是可選的

調用該函數:

//此三個調用等價bool b1 = pf("hello", "goodbye");bool b2 = (*pf)("hello", "goodbye");bool b3 = lengthCompare("hello", "goodbye");

參考:C++Primer第五版

相關文章:

第四章C++:運算式概念-運算子的應用

第五章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.