C++の関数宣言(プロトタイプ宣言)と「値渡し」の基本

C++プログラムは、必ず main という名前の関数から実行が開始されます。この main 関数はプログラム全体のエントリーポイント(入口)であり、その処理が終了するとプログラムが終了します。

main 関数も関数の一種であり、int main() と定義されます。これは「OS(オペレーティングシステム)に対して int 型の整数値を返す」という意味を持ちます。main 関数内の return 0; という文は、プログラムの実行を終了し、「正常に終了しました」という 0 をOSに伝える役割を果たします。

目次

関数宣言(プロトタイプ宣言)の必要性

C++のコンパイラは、ソースコードを基本的に上から下へと順に読み解いていきます。このルールが、関数を定義する順序において重要になります。

もし、main 関数の中で、main 関数よりも**後方(下方)**で定義されている関数を呼び出そうとすると、コンパイラはその関数をまだ「知らない」ため、エラーとなります。

コンパイルエラーになる例

#include <iostream>

int main() {
    // コンパイルエラー!
    // コンパイラは、この時点で 'calculateTotalCost' が何者かを知らない。
    int total = calculateTotalCost(1500, 5); 
    
    std::cout << "合計金額: " << total << "円\n";
    return 0;
}

// 関数の定義が main よりも後にある
int calculateTotalCost(int basePrice, int quantity) {
    return basePrice * quantity;
}

この問題を解決するのが 関数宣言(Function Declaration)、またはプロトタイプ宣言です。

関数宣言は、「こういう名前で、こういう引数を取り、こういう型を返す関数が、このファイルのどこかに(後で)定義されています」という予告をコンパイラに伝える役割を持ちます。

関数宣言は、通常、main 関数よりも前や、ヘッダファイルに記述されます。

関数宣言による解決

#include <iostream>

// --- 関数宣言 (プロトタイプ宣言) ---
// これにより、コンパイラは main の時点で calculateTotalCost の存在を知ることができる。
int calculateTotalCost(int basePrice, int quantity);

int main() {
    // 今度はエラーにならない
    int total = calculateTotalCost(1500, 5); 
    
    std::cout << "合計金額: " << total << "円\n";
    return 0;
}

// --- 関数の定義 (本体) ---
// 関数の定義は main の後でも良い
int calculateTotalCost(int basePrice, int quantity) {
    return basePrice * quantity;
}

このように、呼び出す側の関数(main)よりも、呼び出される側の関数(calculateTotalCost)の定義が後方にある場合は、必ず前方で関数宣言を行う必要があります。


値渡し (Pass-by-Value)

関数を呼び出す際、実引数(呼び出し側で渡す値)が仮引数(関数側で受け取る変数)にどのように渡されるかは非常に重要です。C++における最も基本的な方法は「値渡し(Pass-by-Value)」です。

「値渡し」とは、関数を呼び出す際に、実引数の値そのものがコピーされて、そのコピーが関数の仮引数に渡される仕組みです。

値渡しのメリット:呼び出し元の保護

値渡しの最大のメリットは、関数内で仮引数(コピー)の値をいくら変更しても、呼び出し元の実引数(オリジナル)の変数は一切影響を受けないことです。

これにより、関数が呼び出し元の状態を意図せず破壊してしまう「副作用」を防ぐことができ、コードの安全性が高まります。

値渡しのサンプルコード

以下の例では、simulateNextYear という関数が「現在の年齢」を受け取りますが、これはコピーであるため、main 関数内の userAge 変数は変化しません。

#include <iostream>

// currentAge は「値渡し」で受け取る
// main の userAge の「コピー」が currentAge に入る
void simulateNextYear(int currentAge) {
    // 関数内で仮引数(コピー)の値を変更する
    currentAge = currentAge + 1;
    
    std::cout << "  (関数内) 1年後は " << currentAge << " 歳です。\n";
}

int main() {
    int userAge = 30; // 呼び出し元のオリジナル変数

    std::cout << "(呼び出し前) 現在の年齢は " << userAge << " 歳です。\n";

    // userAge (30) の「コピー」が関数に渡される
    simulateNextYear(userAge);

    std::cout << "(呼び出し後) 現在の年齢は " << userAge << " 歳です。\n";
    
    return 0;
}

実行結果:

(呼び出し前) 現在の年齢は 30 歳です。
  (関数内) 1年後は 31 歳です。
(呼び出し後) 現在の年齢は 30 歳です。

実行結果が示す通り、関数内で currentAge31 に変更されても、main 関数に戻った後の userAge30 のままです。これが「値渡し」による呼び出し元変数の保護機能です。

まとめ

  • C++コンパイラはコードを上から下に読むため、main 関数より後で定義する関数は、main より前に**関数宣言(プロトタイプ宣言)**が必要です。
  • C++のデフォルトの引数渡しは「値渡し」であり、実引数のコピーが関数に渡されます。
  • 値渡しにより、関数内で引数の値を変更しても、呼び出し元の変数は影響を受けず、コードの安全性が高まります。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次