C/C++における参照とポインタの違いと使い分け
参照変数(Reference)とは
参照変数とは、すでに存在する変数につける「別名(エイリアス)」のことです。参照は一度ある変数に結び付くと、後から別の変数を参照するよう変更することはできません。また、宣言時に必ず初期化する必要があり、NULL(何も参照しない状態)にすることもできません。参照変数を宣言するには、演算子「&」を使用します。
参照変数の構文
datatype variable_name; // 変数の宣言 datatype& refer_var = variable_name; // 参照変数の宣言
各要素の意味は次の通りです。
datatype − int、char、float など、変数のデータ型です。
variable_name − ユーザーが指定する元の変数名です。
refer_var − 参照変数の名前です。
参照変数の使用例
#include <iostream>
using namespace std;
int main() {
int a = 8;
int& b = a; // a の参照 b を作成
cout << "The variable a: " << a;
cout << "\nThe reference variable b: " << b;
return 0;
}
出力結果
The variable a: 8 The reference variable b: 8
この例では、b は a の別名として動作するため、b を出力すると a と同じ値「8」が表示されます。つまり、b への代入はそのまま a への代入と同じ意味になります。
ポインタ(Pointer)とは
ポインタとは、他の変数の「メモリアドレス」を格納するための変数です。変数にメモリが割り当てられると、ポインタはその変数のアドレスを指します。ポインタは宣言時の初期化を省略できるほか、後から別のアドレスを代入して指し先を変更したり、NULL を代入したりすることが可能です。
ポインタの構文
datatype *variable_name;
各要素の意味は次の通りです。
datatype − int、char、float など、指し先となる変数のデータ型です。
variable_name − ユーザーが指定するポインタ変数の名前です。
ポインタの使用例
#include <stdio.h>
int main() {
int a = 8;
int *ptr;
ptr = &a; // a のアドレスを ptr に代入
printf("Value of variable: %d\n", a);
printf("Address of variable: %p\n", (void*)ptr);
printf("Value pointer variable: %d\n", *ptr);
return 0;
}
出力結果
Value of variable: 8 Address of variable: 0x7ffd5c1a34ac Value pointer variable: 8
※ 表示されるアドレスは実行環境や実行のたびに変わります。なお、アドレスを出力する際は、書式指定子に %d ではなく %p を使用するのが正しい方法です。
参照とポインタの主な違い
参照とポインタはどちらも変数を間接的に扱う仕組みですが、以下のような違いがあります。
- 指し先の変更: 参照は初期化後に変更できませんが、ポインタは自由に変更できます。
- NULL の扱い: 参照は NULL になれませんが、ポインタは NULL を持てます。
- 初期化: 参照は宣言時に必ず初期化が必要ですが、ポインタは宣言のみでも可能です。
- 算術演算: ポインタにはインクリメントなどの演算ができますが、参照にはできません。
- 可読性: 参照は通常の変数と同じように扱え、間接演算子(*)が不要なためコードが読みやすくなります。
使い分けの目安
関数の引数で値を受け渡し、NULL を許したくない場合は参照が適しています。一方、実行中に指し先を切り替えたい場合や「何も指していない」状態を表現したい場合、配列や動的メモリを操作したい場合はポインタを使うのが一般的です。なお、C 言語には参照機能がないため、必然的にポインタを使用することになります。
-
C++で仮想デストラクタを使うべき場面とは?ポリモーフィックな基底クラスの注意点
『Effective C++』におけるスコット・マイヤーズの助言 スコット・マイヤーズは名著『Effective C++』の中で、仮想デストラクタについて次のように述べています。 「クラスが仮想関数をひとつでも持つなら、そのクラスは仮想デストラクタを持つべきである。一方、基底クラスとして設計されていないクラスや、ポリモーフィックに扱われることを意図していないクラスは、仮想デストラクタを宣言すべきではない」 つまり、ポリモーフィックな基底クラスでは、デストラクタを必ず仮想関数として宣言するのが原則です。 仮想デストラクタがないと何が起きるのか 問題が発生するのは、派生クラスのコンストラクタでオ
-
C/C++の前方宣言(フォワード宣言)とは?使える場面と書き方を解説
C/C++における前方宣言(フォワード宣言)とは、クラスや関数の完全な定義よりも前に、その存在だけをコンパイラへ伝える仕組みです。前方宣言を行うことで、それ以降のコードは「Personという名前のクラスが存在する」ということを認識できるようになります。コンパイラはその名前を見つけてもエラーを出さずに処理を進められ、実際のクラス定義は後の段階でリンカによって解決されます。前方宣言の基本的な例class Person; void myFunc(Person p1) { // ... } class Person { // ここにクラス定義を記述 };このコードがどう動くのかこの