それらの間にある種の微妙な違いがあります:
void a1(float &b) {
b=1;
};
a1(b);
そして
void a1(float *b) {
(*b)=1;
};
a1(&b);
?
どちらも同じことを行います(またはmain()からのように見えます)が、最初のコードは明らかに短いですが、私が見るコードのほとんどは2番目の表記を使用しています。違いはありますか?たぶん、フロートではなくオブジェクトである場合は?
どちらも同じことを行いますが、1つは参照を使用し、もう1つはポインターを使用します。
はい。 *
表記法は、スタック上で渡されるのはポインター、つまり何かのアドレスであることを示しています。 &
は、それが参照だと言います。効果は似ていますが、同一ではありません。
2つの場合を考えてみましょう。
void examP(int* ip);
void examR(int& i);
int i;
examP
を呼び出すと、
examP(&i);
アイテムのアドレスを取得してスタックに渡します。 examR
を呼び出すと、
examR(i);
必要ありません。現在、コンパイラは「何らかの形で」参照を渡します。つまり、実際には、i
のアドレスを取得して渡します。コード側では、
void examP(int* ip){
*ip += 1;
}
ポインタを間接参照する必要があります。 ip += 1
は非常に異なることをします。
void examR(int& i){
i += 1;
}
常にi
の値を更新します。
詳細については、「参照による呼び出し」と「値による呼び出し」を参照してください。 &
の概念は、参照によるC++呼び出しを提供します。
参照を含む最初の例では、b
をNULLにすることはできません。ポインターの例では、b
がNULLポインターになる場合があります。
ただし、is参照を介してNULLオブジェクトを渡すことは可能ですが、扱いにくいため、呼び出されたプロシージャはエラーだと想定できます。
a1(*(float *)NULL);
2番目の例では、callerは変数名の前に「&」を付けて変数のアドレスを渡す必要があります。
これは利点かもしれません-呼び出し側は、値で渡していると思ったときに参照として変数を渡すことで、変数を誤って変更することはできません。
構文糖とは別に、唯一の本当の違いは、nullになるポインターである関数パラメーターの機能です。そのため、nullケースを適切に処理する場合、ポインターバージョンはより表現力豊かになります。 nullケースには、特別な意味を付加することもできます。参照バージョンは、ヌル機能なしで指定されたタイプの値でのみ動作できます。
あなたの例では機能的に、両方のバージョンが同じことをします。
最初の方法には、呼び出し側で透過的であるという利点があります。演算子がどのように見えるか想像してください。
cin >> &x;
そして、スワップ呼び出しにとっては見苦しい
swap(&a, &b);
Aとbを交換します。そして、最初に住所を取得しなければならないときよりもずっと良く見えます。ちなみに、bjarne stroustrupは、参照の主な理由は、特にオペレーターにとって、呼び出し側で追加された透明性だったと書いています。また、次のことが明らかになっていないことも確認してください
&a + 10
Aの内容に10を追加し、その演算子+を呼び出すか、またはaへの一時ポインタに10を追加するかどうか。組み込みのオペランド(ポインターや整数など)のみに対して演算子をオーバーロードできないという不可能性に加えてください。参照はこのクリスタルを明確にします。
ポインターは、「ヌル」を入れたい場合に便利です。
a1(0);
次に、a1では、メソッドはポインターを0と比較し、ポインターがオブジェクトを指しているかどうかを確認できます。
注目に値する大きな違いの1つは、外で起こっていることです。
a1(something);
または:
a1(&something);
関数/メソッドで引数が変更されていない場合(常に自動/一時オブジェクトを渡すこともできます)、参照によって引数を渡します(常にconst one :))、ポインタで渡し、ユーザー/引数が内部で意図的に変更される可能性があるメソッドを呼び出すコードのリーダー。