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 歳です。
実行結果が示す通り、関数内で currentAge が 31 に変更されても、main 関数に戻った後の userAge は 30 のままです。これが「値渡し」による呼び出し元変数の保護機能です。
まとめ
- C++コンパイラはコードを上から下に読むため、
main関数より後で定義する関数は、mainより前に**関数宣言(プロトタイプ宣言)**が必要です。 - C++のデフォルトの引数渡しは「値渡し」であり、実引数のコピーが関数に渡されます。
- 値渡しにより、関数内で引数の値を変更しても、呼び出し元の変数は影響を受けず、コードの安全性が高まります。
