はじめに
C++のクラスでは、メンバ関数の「宣言(プロトタイプ)」をクラス定義内で行い、「実装(処理内容)」をクラスの外部で行うのが一般的です。しかし、処理が非常に短い関数の場合、宣言と実装を分けて書くのが少し冗長に感じられることがあります。
このような場合に、クラス定義の中でメンバ関数の処理内容まで直接記述することができます。このように定義された関数は、コンパイラによって「インライン関数」として扱われ、パフォーマンスが向上する可能性があります。
この記事では、メンバ関数をインラインで実装する方法と、通常の(非インラインの)実装方法との違いについて解説します。
インライン関数と通常関数のサンプルコード
このコードは、Product
クラスの中に、2種類のメンバ関数を定義します。
getID()
: インライン関数として、クラス定義の中で実装します。display()
: 通常の関数として、クラス定義の外で実装します。
完成コード
#include <iostream>
#include <string>
using namespace std;
class Product {
private:
int id;
string name;
public:
// コンストラクタ
Product(int i, string n) {
id = i;
name = n;
}
// --- 1. インライン関数 ---
// クラス定義の中で、処理内容まで記述する
int getID() {
return id;
}
// --- 2. 通常のメンバ関数(プロトタイプ宣言のみ) ---
void display();
};
// --- 通常のメンバ関数の実装 ---
void Product::display() {
cout << "ID: " << id << ", 商品名: " << name << endl;
}
int main() {
Product item(101, "高機能マウス");
// 通常のメンバ関数を呼び出し
item.display();
// インライン関数を呼び出し
cout << "取得したID: " << item.getID() << endl;
return 0;
}
コードの解説
1. インライン関数 (getID
)
int getID() {
return id;
}
getID
関数は、Product
クラスの定義ブロック {}
の内側に、その処理内容 { return id; }
まで全て記述されています。このように記述された関数は、コンパイラに対して「この関数をインライン展開してください」というヒント(指示)になります。
インライン展開とは? 通常、関数が呼び出されると、プログラムの実行は関数の本体がある場所にジャンプし、処理が終わると元の場所に戻ってきます。このジャンプには、ごくわずかながらコストがかかります。
インライン関数は、コンパイラが「呼び出し」のコードを、関数の処理内容そのものに直接置き換えることがあります。これにより、関数呼び出しのコストがなくなり、パフォーマンスが向上する可能性があります。
2. 通常のメンバ関数 (display
)
void display();
のように、クラス定義の中では関数のプロトタイプ宣言だけを行い、実際の処理内容は void Product::display() { ... }
のようにクラスの外側で実装しています。これがC++の標準的なメンバ関数の実装方法です。
インライン関数の使いどころ
インライン化は、関数呼び出しのオーバーヘッドを削減しますが、コードが展開されるため、多用すると最終的な実行ファイルのサイズが大きくなるというデメリットもあります。
経験則として、インライン化するのは、getID()
のように、処理が1〜2行で終わるような、ごくごく短い関数に限定するのが一般的です。
private
なメンバ変数の値を返すだけの「ゲッター」や、値を設定するだけの「セッター」などが、インライン関数の良い候補となります。
まとめ
今回は、C++のインライン関数の基本的な使い方を解説しました。
- クラス定義の中で処理内容まで実装されたメンバ関数は、インライン関数となる。
- 関数呼び出しのコストが削減され、パフォーマンスが向上する可能性がある。
- 処理がごく短い関数(ゲッター、セッターなど)での使用に限定するのが一般的。
インライン関数は、パフォーマンスを最適化するための一つの手段ですが、可読性やファイルサイズの観点から、適切に使い分けることが重要です。