[解決済み] C言語とC++の「参照渡し」は具体的にどう違うのでしょうか?
質問
参照渡しと言う言葉はCとC++の開発者が同じように使っていますが、それぞれ違う意味で使われているようです。それぞれの言語におけるこの等閑視されたフレーズの違いは一体何なのでしょうか?
どのように解決するのですか?
をすでに扱っている質問もあります。 参照渡しと値渡しの違いについて . 要するに、関数に引数を値で渡すということは、その関数が引数のコピーを持つということです - その 値 がコピーされます。そのコピーを変更しても、元のオブジェクトは変更されません。しかし、参照渡しの場合、関数内のパラメータは を参照しています。 関数内部での変更は外部にも反映されます。
残念ながら、quot;pass by valueとquot;pass by referenceの2つの表現があり、混乱を招く可能性があります。特にC言語出身のC++プログラマーにとって、ポインタと参照がなかなか馴染まないのは、このためでもあると思います。
C
C言語では、技術的な意味で、すべてが値で渡されます。つまり、関数に引数として与えたものは、その関数にコピーされるのです。例えば、ある関数を呼び出すと
void foo(int)
で
foo(x)
の値をコピーします。
x
のパラメータとして使用します。
foo
. これは、簡単な例で見ることができます。
void foo(int param) { param++; }
int main()
{
int x = 5;
foo(x);
printf("%d\n",x); // x == 5
}
の値は
x
にコピーされます。
foo
で、そのコピーがインクリメントされる。その
x
で
main
は元の値を持ち続けます。
ご存知のように、オブジェクトはポインタ型にすることができます。例えば
int* p
が定義する
p
へのポインタとして使用します。
int
. 以下のコードでは、2つのオブジェクトを導入していることに注意する必要があります。
int x = 5;
int* p = &x;
1つ目のタイプは
int
という値を持っています。
5
. 2 番目のタイプは
int*
であり、その値は最初のオブジェクトのアドレスである。
関数にポインタを渡す場合も、値で渡すことになります。そのポインタが含むアドレスは関数にコピーされます。その ポインタ を変更しても、関数の外側のポインタは変わりません。 を指しているオブジェクトを は関数の外にあるオブジェクトを変更します。しかし、なぜでしょうか?
同じ値を持つ2つのポインタは常に同じオブジェクトを指すので(同じアドレスを含む)、指されているオブジェクトは両方を通してアクセスし、変更することができます。このため、実際には参照が存在しないにもかかわらず、指し示されたオブジェクトを参照渡ししたかのようなセマンティクスが実現されます(C言語には単純に参照が存在しない)。
void foo(int* param) { (*param)++; }
int main()
{
int x = 5;
foo(&x);
printf("%d\n",x); // x == 6
}
を渡すときに言うことができます。
int*
を関数に渡すと、その
int
が指し示すのは参照渡しですが、実際には
int
ポインタが関数にコピーされただけで、実際にはどこにも渡されていません。このため、口語的な
1
値渡し、参照渡しという意味です。
この用語の使い方は、規格内の用語に裏打ちされている。ポインタ型がある場合、そのポインタが指す型はその
参照型
. つまり、参照される型は
int*
は
int
.
A ポインタ型 は、関数型、オブジェクト型、あるいは不完全な という型があります。 参照型 .
一方、単項演算子
*
演算子(例えば
*p
は、標準ではインダイレクトと呼ばれ、一般にはポインタのデリファレンスとも呼ばれます。これは、C言語における「参照渡し」の概念をさらに推し進めたものです。
C++
C++はC言語から多くの機能を導入していますが、その中にポインタがあり、この「参照渡し」という口語的な形式は今でも使うことができます。
*p
は、まだデリファレンス
p
. しかし、この用語を使うと混乱します。というのも、C++はCにはない機能、つまり、本当に
リファレンス
.
型の後にアンパサンドが続くものは
参照型
2
. 例えば
int&
への参照です。
int
参照型を受け取る関数に引数を渡す場合、オブジェクトは本当に参照で渡されます。ポインタもなければ、オブジェクトのコピーもありません。関数内の名前は、実際には渡されたオブジェクトと全く同じものを指しているのです。上の例と対比してみましょう。
void foo(int& param) { param++; }
int main()
{
int x = 5;
foo(x);
std::cout << x << std::endl; // x == 6
}
ここで
foo
関数は、パラメータとして
int
. ここで
x
,
param
は正確に同じオブジェクトを参照しています。インクリメント
param
の値に目に見える変化があります。
x
となり、今度は
x
は6という値を持っています。
この例では、値で渡されたものは何もありません。何もコピーされていないのです。C言語では、参照渡しは単にポインタを値で渡すだけでしたが、C++では純粋に参照渡しをすることができます。
参照渡しという用語にはこのような曖昧さがあるため、C++の文脈では参照型を使用する場合にのみ使用するのがよいでしょう。ポインタを渡している場合は、参照渡しではなく、値によるポインタ渡しです(もちろん、ポインタへの参照を渡している場合は別です!例:「ポインタへの参照」)。
int*&
). しかし、ポインタが使われているときに、quot; pass by reference"を使うことがあるかもしれませんが、これで少なくとも何が実際に起こっているかはわかりましたね。
その他の言語
他のプログラミング言語では、さらに複雑なことが起こります。Javaなどでは、持っているすべての変数がオブジェクトへの参照として知られています(C++の参照とは異なり、ポインタのようなものです)が、これらの参照は値で渡されます。そのため、関数に参照渡ししているように見えても、実際には参照を値で関数にコピーしていることになります。このC++の参照渡しとの微妙な違いは、渡された参照に新しいオブジェクトを代入するときに気づかされます。
public void foo(Bar param) {
param.something();
param = new Bar();
}
この関数を Java で呼び出す場合、型は
Bar
を呼び出すと
param.something()
は、あなたが渡したのと同じオブジェクトに対して呼び出されます。これは、あなたがオブジェクトへの参照を渡したからです。しかし、新しい
Bar
に代入されます。
param
このとき、関数の外側にあるオブジェクトは、相変わらず古いオブジェクトのままです。新しいオブジェクトは外からは決して見えません。それは
foo
は新しいオブジェクトに再割り当てされています。このような参照の再割り当ては、C++の参照では不可能です。
1 口語的というのは、C++の参照渡しという意味よりも真実味がないという意味ではなく、C++には参照型があるので、純粋に参照渡しをしているという意味です。 参照 . C言語の意味は、実際の値による受け渡しを抽象化したものです。
2 もちろん、これらはlvalueの参照であり、C++11ではrvalueの参照もある。
関連
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] 変数を参照渡しする方法を教えてください。
-
[解決済み] MVPとMVC、その違いは何ですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】C++の余分な資格エラー
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)