C++の関数リロード

3975 ワード

重荷の概念
「オーバーロード」(Overload)--同じ識別子は異なるコンテキストで異なる意味を持つ.
  • 関数リロード(Function Overload)
  • 同じ関数名で異なる関数を定義する
  • 関数名が異なるパラメータと組み合わせたときの関数の意味が異なる

  • コードで栗を挙げます.
    int func(int x)
    {
        return x;
    }
    
    int func(int a, int b)
    {
        return a + b;
    }
    
    int func(const char* s)
    {
        return strlen(s);
    }
    

    上記のコードの3つのfunc関数は異なる意味を持つ.
    関数の再ロードは、少なくとも次の条件を満たします.
  • パラメータ個数が異なる
  • パラメータタイプが異なる
  • パラメータ順序が異なる
  • ここで、コード栗で言えば、 についてです.
    #include 
    
    int func(int a, int b, int c = 0)
    {
        return a * b * c;
    }
    
    int func(int a, int b)
    {
        return a + b;
    }
    
    
    int main(int argc, char *argv[])
    {
        int c = func(1, 2);
        
        return 0;
    }
    

    上記のコードでは、2つのfunc関数はリロードの条件に合致するが、最初のfunc関数にはデフォルトのパラメータがあるため、呼び出すときにこのパラメータを渡さなくてもよいが、渡さなければ2番目のfunc関数と衝突する.ここでは曖昧さを引き起こすため、コンパイルが通過しません.
    リロード関数呼び出しガイドライン
    コンパイラがリロード関数を呼び出すガイドライン
  • すべての同名関数を候補とする
  • 実行可能な候補関数の検索を試みる
  • 実パラメータ
  • を正確にマッチング
  • は、デフォルトのパラメータによって実パラメータ
  • と一致することができる.
  • は、デフォルトのタイプ変換によって実パラメータ
  • に一致する.
  • 照合に失敗しました
  • が最終的に探した候補関数が一意でない場合、二義性が現れ、コンパイルに失敗した
  • すべての候補者に一致できません.関数は定義されていません.コンパイルに失敗しました.

  • 栗を挙げます.
    #include 
    
    int add(int a, int b)  // int(int, int)
    {
        return a + b;
    }
    
    int add(int a, int b, int c) // int(int, int, int)
    {
        return a + b + c;
    }
    
    int main()
    {
        printf("%p
    ", (int(*)(int, int))add); printf("%p
    ", (int(*)(int, int, int))add); return 0; }

    コードの実行結果は次のとおりです.
    0x10fa48f00
    0x10fa48f20
    

    2つのadd関数が異なる関数ポインタであることがわかる.コンパイラがコンパイルするとき、基準に基づいて2つの異なる関数であることを認識し、それぞれシンボルテーブルに配置します.シンボルテーブルの内容は以下の通りです.
    0000000000000000 T __Z3addii
    0000000000000020 T __Z3addiii
    0000000000000040 T _main
                     U _printf
    

    シンボルテーブルから,__Z3addii__Z3addiiiは2つのadd関数に違いない.したがって、コンパイラの内部では、2つの関数をそれぞれシンボルテーブルに格納します.
    注意事項
  • リロード関数は本質的に互いに独立した異なる関数
  • である.
  • リロード関数の関数タイプが異なる
  • 関数の戻り値は、関数のリロードの根拠とすることはできない
  • .
  • 関数リロードは、関数名とパラメータリストによって決定される
  • である.
    したがって,コードを記述する過程で,関数名とパラメータリストによって決定される関数戻り値を根拠にすることはできない.
    関数リロードと関数ポインタ
    3つの関数があると仮定します.
    int func(int x)
    {
        return x;
    }
    
    int func(int a, int b)
    {
        return a + b;
    }
    
    int func(const char* s)
    {
        return strlen(s);
    }
    

    3つの関数は、関数の再ロードの基準に合致しますが、次のように関数ポインタを定義します.
    typedef int(*PFUNC)(int a);
    
    int c= 0;
    
    PFUNC p = func;
    
    c = p(1);
    

    関数ポインタを定義し、intタイプの値を入力します.上記の3つの関数のうちどれを呼び出しますか?
    実はあなたの心の中の答えに完全に合っていて、最初の呼び出しです.しかし、いくつか注意しなければならないことがあります.
    関数の再ロードが関数ポインタに遭遇した場合:
  • リロード関数名を関数ポインタに付与する場合
  • 1、リロード規則に従って関数ポインタパラメータリストと一致する候補者
  • を選択する.
  • 2、候補と厳密に一致する関数タイプと関数ポインタの関数タイプ
  • 、ここでのタイプは、
  • を含む.

    注意:
  • 関数のリロードは、必然的に同じ役割ドメインで
  • に発生する.
  • コンパイラは、パラメータリストまたは関数タイプで関数選択
  • を行う必要がある.
  • は、関数名から直接リロード関数を得ることができないエントリアドレス
  • である.
    C++とC相互呼び出し
  • 実際のエンジニアリングにおけるC++とCコードの相互呼び出しは避けられない
  • である.
  • C++コンパイラC言語対応コンパイラ
  • C++コンパイラはC++コンパイル方式
  • を優先的に使用する.
  • externキーワードはC++コンパイラにC方式のコンパイルを強制させることができる:
  • extern 'C'
    {
        //do C-style compilation here
    }
    

    では、どのようにしてCコードがCでしかコンパイルされないことを保証しますか?
    #include 
    
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #include "add.h"
    
    #ifdef __cplusplus
    }
    #endif
    
    
    int main()
    {
       int c = add(1, 2);
       
       printf("c = %d
    ", c); return 0; }
    _cplusplusマクロ定義の使用
  • _cplusplusはC++コンパイラ内蔵の標準マクロ定義
  • である.
  • _cplusplusの意味は、Cコードが統一的なC方式でターゲットファイル
  • にコンパイルされることを確保することである.
    注意事項:
  • C++コンパイラは、Cでリロード関数
  • をコンパイルすることはできません.
  • コンパイル方式は、関数名がコンパイルされたターゲット名を決定する
  • C++コンパイル方式関数名とパラメータリストをターゲット名
  • にコンパイルする.
  • Cコンパイル方式は、関数名のみをターゲット名としてコンパイル
  • を行う.