C++チュートリアルの機能(1)

バックグラウンド

関数は C++ の重要な概念であり、これによりコードの一部をカプセル化し、必要に応じて呼び出すことができます。C++ の関数には次の特徴があります。

  • 関数にはパラメータと戻り値を含めることができます。
  • 関数は他の関数から呼び出すことができます。
  • 関数はオーバーロードできます。つまり、パラメーター リストが異なる限り、同じ名前の複数の関数を定義できます。

関数の定義と呼び出し

C++ では、関数の定義と呼び出しが非常に簡単です。以下は、単純な関数定義と呼び出しの例です。

#include <iostream>

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z << std::endl;
    return 0;
}

この例では、2 つのパラメーター x と y を受け取り、x + y を返す add という関数を定義します。次に、main 関数で add 関数を呼び出し、戻り値を変数 z に代入し、最後に 1 + 2 = 3 を出力します。

関数のパラメータと戻り値

C++ では、関数にパラメーターと戻り値を含めることができます。パラメータと戻り値を含む関数の例を次に示します。

#include <iostream>

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z <<
    std::endl;

// 调用 add 函数,并将返回值赋值给变量 z
}

この例では、2 つのパラメーター x と y を受け取り、x + y を返す add という関数を定義します。次に、main 関数で add 関数を 2 回呼び出し、戻り値をそれぞれ変数 z に代入し、最終的に 1 + 2 = 3 と 3 + 4 = 7 を出力します。

関数のオーバーロード

C++ では、関数をオーバーロードできます。つまり、パラメーター リストが異なる限り、同じ名前の複数の関数を定義できます。関数のオーバーロードの例を次に示します。

#include <iostream>

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

// 定义一个名为 add 的函数,它有三个参数 x、y 和 z,返回值为 x + y + z
int add(int x, int y, int z) {
    return x + y + z;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z << std::endl;

    // 调用 add 函数,并将返回值赋值给变量 z
    z = add(1, 2, 3);
    std::cout << "1 + 2 + 3 = " << z << std::endl;

    return 0;
}

この例では、同じ名前で異なるパラメーター リストを持つ 2 つの関数 add を定義します。これは関数のオーバーロードの例です。関数のオーバーロードを使用すると、異なるパラメーター リストを持つ限り、同じ名前で複数の関数を定義できます。これにより、各関数に異なる名前を付ける必要がなく、関数をより便利に使用できるようになります。

パラメータの受け渡し

C++ では、パラメーターを関数に渡す方法が 2 つあります。値による受け渡しと参照による受け渡しです。

値渡し

値による受け渡しとは、パラメーターの値のコピーを作成し、このコピーを関数に渡すことを指します。関数内でパラメータを変更しても、元のパラメータには影響しません。値渡しの例を次に示します。

#include <iostream>

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    x = x + 1;
    y = y + 1;
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    int c = add(a, b);
    std::cout << "a = " << a << std::endl; // 输出 a = 1
    std::cout << "b = " << b << std::endl; // 输出 b = 2
    std::cout << "c = " << c << std::endl; // 输出 c = 5
    return 0;
}

この例では、2 つのパラメーター x と y を受け取り、x + y を返す add という関数を定義します。次に、main 関数で 3 つの変数 a、b、c を定義し、a と b の値をそれぞれ 1 と 2 として割り当てます。次に、add 関数を呼び出し、a と b をパラメータとして渡しました。add 関数内で x と y の値を変更しますが、これらの変更は a と b の値には影響しません。

参照渡し

参照渡しとは、引数への参照を関数に渡すことを意味します。関数内でパラメータを変更すると、元のパラメータに影響します。以下は参照渡しの例です。

#include <iostream>

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int& x, int& y) {
    x = x + 1;
    y = y + 1;
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    int c = add(a, b);
    std::cout << "a = " << a << std::endl; // 输出 a = 2
    std::cout << "b = " << b << std::endl; // 输出 b = 3
    std::cout << "c = " << c << std::endl; // 输出 c = 6
    return 0;
}

この例では、2 つのパラメーター x と y を受け取り、x + y を返す add という関数を定義します。次に、main 関数で 3 つの変数 a、b、c を定義し、a と b の値をそれぞれ 1 と 2 として割り当てます。次に、add 関数を呼び出し、a と b への参照をパラメータとして渡します。add 関数内で x と y の値を変更します。これは a と b の値に影響します。

どの道を選ぶか

パラメーターの受け渡し方法を選択するときは、次の要素を考慮する必要があります。

  • パラメーターが小さなプリミティブ型 (int、double など) の場合は、値で渡すことができます。
  • パラメーターが大きな構造体またはクラスである場合は、参照によって渡すことができるため、大量のデータのコピーを回避できます。
  • 関数内のパラメーターの値を変更する必要があり、その変更が元のパラメーターに影響を与えたい場合は、参照渡しを使用できます。

関数マッチング

C++ では、関数のマッチングとは、関数を呼び出すときに実際のパラメーターの型と量に応じて、コンパイラーがオーバーロードされた関数のセットから最適に一致する関数を選択するプロセスを指します。関数マッチングは、プログラムがどの関数を呼び出すかを決定する C++ の重要な概念であるため、C++ プログラマが関数マッチングのルールと原則を理解することは非常に重要です。C++ の関数一致ルールはより複雑で、主に次の側面が含まれます。

  • 引数の型の完全一致
  • 引数の型の標準型変換
  • 引数型のユーザー定義型変換
  • 関数テンプレートのマッチング
引数の型の完全一致

関数は、その仮パラメータ型と実際のパラメータ型がまったく同じである場合、完全に一致します。たとえば、次のコードでは、 foo 関数の仮パラメータ型と実際のパラメータ型がまったく同じであるため、完全に一致します。

void foo(int x, double y) {
    // ...
}

int main() {
    int a = 1;
    double b = 2.0;
    foo(a, b); // 精确匹配
    return 0;
}
引数の型の標準型変換

関数の仮パラメータ型が実際のパラメータ型と一致しない場合でも、標準の型変換 (整数昇格、算術型変換、ポインタ型変換など) を通じて実パラメータ型を仮パラメータ型に変換できる場合。の場合、この関数は標準タイプの変換一致です。たとえば、次のコードでは、foo 関数の仮パラメータ型は int で、実際のパラメータ型は short ですが、short 型は整数昇格によって int 型に変換できるため、foo 関数は標準型になります。コンバージョンマッチ:

void foo(int x, double y) {
    // ...
}

int main() {
    short a = 1;
    double b = 2.0;
    foo(a, b); // 标准类型转换匹配
    return 0;
}
引数型のユーザー定義型変換

関数の仮パラメータの型が実パラメータの型と矛盾しており、実パラメータの型を標準の型変換では仮パラメータの型に変換できないが、実パラメータの型はユーザー変換によって仮パラメータの型に変換できる場合。定義された型変換の場合、この関数はユーザー定義の型変換一致となります。たとえば、次のコードでは、foo 関数の仮パラメータの型は double ですが、実際のパラメータの型は int ですが、int 型はユーザー定義の型変換によって double 型に変換できるため、foo 関数は次のようになります。ユーザー定義の型変換一致:

class A {
public:
    operator double() const {
        return 0.0;
    }
};

void foo(double x) {
    // ...
}

int main() {
    A a;
    foo(a); // 用户自定义类型转换匹配
    return 0;
}

上記の例では、foo関数の仮引数の型はdouble、実引数の型はAですが、型Aはユーザー定義型変換によりdouble型に変換できます。具体的には、クラス A は、型 A を double 型に変換する型変換関数演算子 double() を定義します。foo 関数を呼び出すと、コンパイラは自動的にクラス A の型変換関数を呼び出し、型 A を double 型に変換し、変換された double 型を実パラメータとして foo 関数に渡します。

関数テンプレートマッチング

C++ では、関数テンプレートのマッチングはテンプレート引数の推論によって実現されます。関数テンプレートを呼び出すと、コンパイラは実際のパラメータの型に応じてテンプレート パラメータの型を推定し、テンプレート パラメータの型に応じて関数テンプレートを照合します。具体的には、コンパイラは実パラメータの型に基づいてテンプレート パラメータの型を推定し、テンプレート パラメータの型を関数テンプレートの仮パラメータの型と照合します。一致が成功した場合は、関数テンプレートを使用して対応する関数インスタンスが生成されますが、一致しなかった場合はコンパイラによってエラーが報告されます。

関数テンプレート マッチングは非常に柔軟なメカニズムであり、実際のパラメータの型に応じてテンプレート パラメータの型を推定できるため、自動型推定が実現されることに注意してください。ただし、関数テンプレートのマッチングはコンパイル時に実行されるため、特定の構文規則と制限を満たす必要があります。たとえば、関数テンプレートの仮パラメータの型を参照型にすることはできません。そうしないと、テンプレート パラメータの推論が失敗します。関数テンプレートの仮パラメータの型を void 型にすることはできません。それ以外の場合は、コンパイル エラーが発生します。
関数テンプレート マッチングの例を次に示します。

template <typename T>
void foo(T x) {
    std::cout << x << std::endl;
}

int main() {
    foo(1); // T = int
    foo(1.0); // T = double
    foo("hello"); // T = const char*
    return 0;
}

上記のコードでは、テンプレート パラメーター T と仮パラメーター x を持つ関数テンプレート foo を定義します。foo 関数を呼び出すと、コンパイラは実際のパラメータの型に基づいてテンプレート パラメータの型を推定し、テンプレート パラメータの型を関数テンプレートの仮パラメータの型と照合します。たとえば、foo(1) を呼び出すと、コンパイラは T が int であると推測し、foo を使用して対応する関数インスタンスを生成します。foo(1.0) を呼び出すと、コンパイラは T が double であると推測し、 foo を使用して対応する関数インスタンスを生成します。foo("hello") を呼び出すと、コンパイラは T が const char* であると推測し、 foo<const char*> を使用して対応する関数インスタンスを生成します。

やっと

この記事では主に機能に関する内容を紹介していますが、その他の記事については公式アカウント QStack をご覧ください。

おすすめ

転載: blog.csdn.net/QStack/article/details/129827474