C++(6)関数

10576 ワード

第六章関数
関数は名前付きのコードブロックであり、関数を呼び出して対応するコードを実行します.
関数ベース
  • は、演算子(call operator)を呼び出すことによって関数を実行する.その形式は一対の括弧である.
  • 関数の呼び出しは2つの作業(以下)を完了し、このときプライマリ・コール関数(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;
    }

    関数宣言
  • は関数プロトタイプ
  • とも呼ばれる.
  • 関数の3つの要素(戻りタイプ、関数名、パラメータタイプ)は、関数のインタフェースを記述し、関数宣言ではパラメータ名を省略することができる.
  • 関数は、ソースファイルで定義されたヘッダファイルに宣言する必要があります.
  • 分離コンパイル
  • パラメータ伝達
    パラメータが参照タイプの場合、対応する実パラメータにバインドされます.そうでない場合は、実パラメータの値をコピーしてパラメータに割り当てます.
  • 参照パラメータの値を変更する必要がない場合は、定数参照として宣言することが望ましい.

  • main:コマンドラインオプションの処理
    main関数が実行可能ファイルprog内にあると仮定すると、次のオプションをプログラムに渡すことができます.
    prog -d -o ofile data0

    これらのコマンドは、main関数に2つのオプションのパラメータで渡されます.
    int main(int argc, char *argv[]) {...}
    // :
    int main(int argc, char **argv) {...}

    実パラメータがmain関数に渡されると、argvの最初の要素はプログラムの名前または空の文字列を指し、次の要素はコマンドラインで提供された実パラメータを一度に渡します.最後のポインタは要素値を0に保証するだけです.
  • 上記のコマンド動作例:
  • argc = 5;
    argv[0] = "prog";
    argv[1] = "-d";
    argv[2] = "-o";
    argv[3] = "ofile";
    argv[4] = "data0";
    argv[5] = 0;

    変形可能パラメータを含む関数
  • C++11新しい標準は、異なる数の実パラメータを処理できる2つの方法を記述する関数を提供します.
  • すべての実パラメータタイプは同じで、initializerという名前を渡すことができます.Listの標準ライブラリタイプ.
  • 実パラメータタイプは異なり、可変パラメータテンプレートと呼ばれる特殊な関数を記述することができます.

  • C++には、省略記号という特殊なパラメータタイプもあります.可変数の実パラメータを渡すことができます.この機能は一般にC関数と対話するインタフェースプログラムにのみ用いられる.
  • initializer_リストパラメータ
  • そのタイプは、同名のヘッダファイルの
  • に定義される.
  • は、
  • を提供する.
    initializer_list lst;    //     ,T        
    initializer_list 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ヘッダファイルは2つの前処理変数を定義し、それぞれ成功と失敗を表す:
    return EXIT_FAILURE;
    return EXIT_SUCCESS;
    //          ,          std::,    using     。
  • .
    配列ポインタを返す
  • タイプ別名
    typedef int arrT[10];   //arrT       ,         10      
    using arrT = int[10];   //      
    arrT* func(int i);      //func        10         
  • を使用
  • は、
    Type (*function(parameter_list)) [dimension]
    //Type                  
    //dimension       
    //  :
    int (*func(int i)) [10];
  • の形式で配列ポインタを返す関数を宣言する.
  • テールバックタイプ(C++11)
    auto func(int i) -> int(*)[10];
  • を使用する.
  • 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;  //           
    }
  • を使用
    関数の再ロード
    同じ役割ドメイン内のいくつかの関数の名前が同じで、パラメータリストが異なる場合、オーバーロード関数と呼びます.
  • では、2つの関数が戻りタイプを除いてすべての要素が同じであることは許可されません.
  • リロードと役割ドメイン:現在の役割ドメインに必要な名前が見つかったら、コンパイラは外層役割ドメインの同名エンティティを無視します.

  • とくしゅようげんごとくせい
    デフォルトの実パラメータ、インライン関数、constexpr関数の3つの関数に関する言語特性を紹介します.
    デフォルトの実パラメータ
  • デフォルトの実パラメータを含む関数を呼び出す場合は、その実パラメータを含んでもよいし、省略してもよい.
  • あるパラメータにデフォルト値が付与されると、その後のすべてのパラメータにデフォルト値が必要になります.

  • インライン関数
    呼び出し関数は一般的に等価式を求める値よりも遅く、インライン関数は関数呼び出しのオーバーヘッドを回避します.-関数をインライン関数として指定します.通常は、呼び出しポイントごとに「インライン」に展開されます.
    constexpr関数
  • 関数の戻りタイプとすべてのパラメータタイプは、フォント値タイプでなければなりません.
  • 関数にはreturn文が1つしかない必要があります.
  • constexpr関数は暗黙的にインライン関数として指定される.

  • インライン関数とconstexpr関数は、通常、ヘッダファイルに定義されます.
    デバッグヘルプ
    プログラムにはデバッグ用のコードを含めることができますが、これらのコードはプログラムの開発時にのみ使用されます.アプリケーションの作成が完了したら、デバッグコードをブロックします.この方法は2つの前処理機能を用いた:assertとNDEBUG.
    assertプリプロセッシングマクロ
    #include 
    
    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 _ _他にも4つの名前があります.
    _ _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第5版