C++プログラミングにおいて、関数は非常に重要な役割を果たします。
しかし、初心者にとっては関数の使い方がわかりづらいこともあります。
そこで本記事では、C++での関数の基礎から応用までをサンプルコードを交えて解説していきます。
C++での関数の基礎
C++において、関数はプログラムを構成する重要な要素の一つです。
関数を使うことで、同じ処理を何度も書く必要がなくなり、コードの再利用性が高まります。ここでは、C++での関数の基礎について解説します。
関数の定義
C++で関数を定義するには、以下のような構文を使います。
戻り値の型 関数名(引数1の型 引数1, 引数2の型 引数2, ...) {
// 処理内容
return 戻り値;
}
例えば、Hello, World!
と表示するだけの関数を定義する場合は以下のようになります。
void hello() {
std::cout << "Hello, World!" << std::endl;
}
この場合、戻り値がvoid
となっています。void
は「何も返さない」という意味です。また、引数もありません。
関数の呼び出し
関数を定義したら、その関数を呼び出すことができます。以下は先程定義したhello()
関数を呼び出す例です。
int main() {
hello();
return 0;
}
この場合、main()
関数からhello()
関数が呼び出されます。実行結果として、Hello, World!
が表示されます。
引数の渡し方
引数とは、関数に渡すデータです。引数を使うことで、同じ処理でも異なるデータに対して適用することができます。引数を受け取るためには、以下のように引数リストを追加します。
戻り値の型 関数名(引数1の型 引数1, 引数2の型 引数2, ...) {
// 処理内容
return 戻り値;
}
例えば、「Hello, ○○!」と表示するだけの関数を定義し、名前を引き渡す場合は以下のようになります。
void hello(std::string name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
この場合、引き渡された名前が表示されます。「○○」部分に任意の名前が入力されるため、「Hello, ○○!」というメッセージが表示されます。
#include <iostream>
#include <string>
void hello(std::string name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
int main(){
hello("アカリ");
return 0;
}
Hello, アカリ!
戻り値の返し方
戻り値とは、処理結果や計算結果などを返すために使用します。戻り値を返すためには、以下のように戻り値リストを追加します。
戻り値の型 関数名(引数1の型 引数名 , 引数2の型 引数名 , ...) {
// 処理内容
return 戻り値;
}
例えば、a + b
を計算してその結果(和) を返す add()
関数を定義する場合は以下のようになります。
int add(int a, int b) {
int sum = a + b;
return sum;
}
この場合、a + b
の計算結果(和) を return
文で返しています。
#include <iostream>
int add(int a, int b) {
int sum = a + b;
return sum;
}
int main(){
std::cout << add(3, 5) << std::endl;
return 0;
}
8
関数の種類
C++には様々な種類の関数があります。ここでは、ユーザー定義関数、標準ライブラリ関数、インライン関数、そしてラムダ式について説明します。
ユーザー定義関数
ユーザー定義関数とは、プログラマが自分で作成した関数のことです。
これらの関数は、プログラム内で何度でも呼び出すことができます。また、同じ処理を複数回書く必要がある場合にも便利です。
以下は、2つの整数を加算するユーザー定義関数Addition()の例です。
int Addition(int a, int b) {
return a + b;
}
このようにして作成されたユーザー定義関数は、他の部分から呼び出すことができます。
int main() {
int result = Addition(3, 4);
std::cout << result << std::endl; // 出力: 7
return 0;
}
標準ライブラリ関数
標準ライブラリ関数とは、C++言語に最初から組み込まれている関数のことです。これらの関数は、プログラマが自分で作成する必要がなく、簡単に使用することができます。
以下は、文字列を大文字に変換するtoupper()
標準ライブラリ関数の例です。
#include <iostream>
#include <cctype>
int main() {
char str[] = "Hello World!";
for (int i = 0; str[i]; i++) {
std::cout << (char)toupper(str[i]);
}
// 出力: HELLO WORLD!
return 0;
}
インライン関数
インライン関数とは、コンパイル時に展開される小さなサブルーチンのことです。
これらの関数は通常のユーザー定義関数よりも高速に実行されます。ただし、コードサイズが大きくなる可能性があるため注意が必要です。
以下は、引用符を除去するインライン関数RemoveQuotes()
の例です。
#include <iostream>
inline std::string RemoveQuotes(std::string str) {
str.erase(std::remove(str.begin(), str.end(), '\"'), str.end());
return str;
}
int main() {
std::string input = "\"Hello World!\"";
std::cout << RemoveQuotes(input) << std::endl; // 出力: Hello World!
return 0;
}
ラムダ式
C++11以降では、「無名」または「匿名」(名前を持たない)オブジェクトを生成するために使用される新しい構文である「Lambda式」を使用することもできます。
Lambda式を使用すると、小さなサブルーチンを作成しやすくなります。
以下は、Hello
という文字列を表示するLambda式PrintHelloWorld()の例です。
#include <iostream>
int main() {
auto PrintHelloWorld = [](){std::cout << "Hello" << std::endl;};
PrintHelloWorld(); // 出力: Hello
return 0;
}
以上がC++言語で使用される主要な4つの種類の関数です。それぞれ異なった目的や特徴を持っています。
関数のオーバーロード
C++では、同じ名前の関数を複数定義することができ、同じ名前で異なる引数を持つ関数を複数定義することを「関数のオーバーロード」と呼びます。
オーバーロードは、プログラムの可読性や保守性を高めるために役立ちます。
オーバーロードされた関数は、以下の条件を満たす必要があります。
- 関数名は同じである。
- 引数リストが異なっている。
- 戻り値の型は異なっていてもよい。
以下は、int型とdouble型の引数を取るadd()関数をオーバーロードした例です。
#include <iostream>
using namespace std;
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
int x = 1, y = 2;
double d1 = 1.5, d2 = 2.5;
cout << add(x, y) << endl; // 出力結果:3
cout << add(d1, d2) << endl; // 出力結果:4.0
return 0;
}
上記コードでは、int型とdouble型それぞれに対応したadd()関数が定義されています。main()関数内でそれぞれ呼び出し、正しく動作していることが確認できます。
関数のポインタ
関数ポインタとは、関数を指すポインタのことです。
C++では、関数もメモリ上に配置されており、そのアドレスを取得することができます。
このアドレスを保持するために、関数ポインタが使用されます。
ポインタの概要
まずはじめに、ポインタについて簡単に説明します。
ポインタとは、変数やオブジェクトなどのメモリ上のアドレスを格納するための変数です。
例えば、int型の変数aがあった場合、そのアドレスを保持するためにint型のポインタpを定義することができます。
int a = 10;
int* p = &a; // pはaのアドレスを保持する
関数ポインタの定義
次に、関数ポインタの定義方法について説明します。関数ポインタは、「戻り値の型 (*変数名)(引数リスト)」という形式で宣言します。例えば、int型を返す引数が2つある関数foo()があった場合、
int foo(int a, int b) {
return a + b;
}
以下のようにしてfoo()への関数ポインタp_fooを定義できます。
int (*p_foo)(int, int) = foo;
関数ポインタの呼び出し
関数ポインタから実際に関数を呼び出す場合は、「(*変数名)(引数リスト)」という形式で記述します。
int result = (*p_foo)(1, 2); // result = 3
また、「変数名(引数リスト)」でも同じ結果が得られます。
int result = p_foo(1, 2); // result = 3
関数ポインタの配列
複数の関数へ同時にアクセスしたい場合は、配列形式で宣言することもできます。
// 引用符内部分は省略可能(typedef)
typedef int (*FuncPtr)(int, int);
FuncPtr funcs[] = {foo, bar};
for (auto func : funcs) {
std::cout << func(1, 2) << std::endl;
}
このようなコードでは、funcs[0]からfoo()へアクセスし、funcs[1]からbar()へアクセスします。
関数ポインタを応用して配列を作ることで、後で実行する関数をまとめておき、任意のタイミングで全部実行するといった事が可能です。
以上がC++での関数ポインタについてです。