3

私はしばらくの間 C++ でプログラミングを行ってきましたが、自分を専門家とは呼べません。この質問は、私が抱えている実際の問題を解決するために尋ねられているのではなく、C++ が何をしているかを理解することに関するものです。

単一のパラメーターを期待する関数があるとします。

void doSomething(SomeClass& ref)
{
    // do something interesting
}

(注: パラメータは SomeClass への参照です) 次に、次のように関数を呼び出します。

int main(int argc, char *argv[])
{
    SomeClass a;
    doSomething(a);
}

なぜこれは正当な C++ なのですか? 関数は SomeClass への参照を想定していますが、静的に割り当てられた SomeClass 型の変数を渡しています。参照はポインタのようなものですよね?参照をポインターに置き換えると、コンパイラーは文句を言います。このように参照がポインターと異なるのはなぜですか?舞台裏で何が起こっているのでしょうか?

これがばかげた質問でしたら申し訳ありません。

4

8 に答える 8

2

参照をポインターに似ていると考えるのをやめれば、これをよりよく理解できると思います。この比較が行われる理由は 2 つあります。

  1. 参照を使用すると、オブジェクトを関数に渡して変更できるようになります。これは、C でのポインターの一般的な使用例でした。
  2. ポインタと参照の実装は、コンパイル後は通常ほとんど同じです。

しかし、それら別のものです。参照は、オブジェクトに新しい名前を付ける方法と考えることができます。int& x = y;は、私が現在 として参照しているオブジェクトに新しい名前を付けたいと言いますy。この新しい名前はxです。これらはどちらも と を識別し、x現在yは両方とも同じオブジェクトを参照しています。

これが、オブジェクト自体を参照として渡す理由です。渡すオブジェクトを参照するために、関数に独自の識別子を持たせたいと言っています。アンパサンドをパラメーター リストに入れないと、オブジェクトが関数にコピーされます。多くの場合、このコピーは必要ありません。

于 2011-04-16T22:27:23.550 に答える
1

おそらく、次の 2 つの関数がある場合に混乱が生じる可能性があります。

void doThingA(int a) {
    a=23;
}
void doThingB(int &a) {
    a=23;
} 

それらへの呼び出しは同じように見えますが、実際には大きく異なります。

int a=10;
doThingA(a);
doThingB(a);

最初のケースである doThingA(int) は、値 10 を持つまったく新しい変数を作成し、それに 23 を割り当てて返します。呼び出し元の元の変数は変更されません。変数が参照渡しされる 2 番目のケース doThingB(int&) では、渡された変数と同じアドレスで新しい変数が作成されます。これは、参照渡しはポインター渡しのようなものだと人々が言うときの意味です。doThingB(int&) が渡された値を変更すると、両方の変数が同じアドレスを共有する (メモリ位置を占有する) ため、呼び出し元の変数も変更されます。

私はそれを、面倒なポインター構文を一切使わずにポインターを渡すものと考えるのが好きです。とはいえ、参照によって渡された変数を変更する関数は混乱を招くと思いますが、私はほとんどそうしません。const参照で渡すか

void doThingB(const int &a);

または、値を変更する場合は、明示的にポインターを渡します。

void doThingB(int *a);
于 2011-04-16T23:45:18.527 に答える
1

「SomeClass 型の静的に割り当てられた変数」を渡すのではなく、.NET でSomeClassスタック上に作成したオブジェクトへの参照を渡しますmain()

あなたの機能

void doSomething(SomeClass& ref)

ain main への参照が渡されるようにします。これ&は、パラメーター リストの型の後に行うことです。

を省略した場合&SomeClassの (aの) コピー コンストラクターが呼び出され、関数は 内のaオブジェクトの新しいローカル コピーを取得しmain()ます。その場合、関数で行ったことは何も表示さrefれませんmain()

于 2011-04-16T22:21:05.553 に答える
1

コードが正しくありません - インスタンスを返すSomeClass a();関数の前方宣言です- そのような宣言は関数スコープでは無効です。aSomeClass

あなたが意味すると仮定するとSomeClass a;

参照は、ほとんどの実用的な点でポインターに非常に似ています。主な違いは、NULL へのポインターを持つことはできるのに対し、NULL への参照を合法的に持つことはできないということです。お気づきのとおり、ポインターと参照の構文は異なります。参照が必要な場所にポインターを渡すことはできません。

参照を「null にすることはできず、他の場所を指すようにすることもできないポインター」と考えれば、ほぼカバーされています。aローカルインスタンスを参照するものを渡しています。doSomethingそのパラメータを変更する場合は、 local を実際に直接変更していますa

于 2011-04-16T22:27:57.850 に答える
1
SomeClass a();

これは関数シグネチャであり、オブジェクトではありません。

そのはず

SomeClass a; // a is an object

その後、コードは有効です。

なぜこれは正当な C++ なのですか?

(前の点を修正したと仮定します)C++標準では、関数属性が参照である場合、名前(左辺値)を持つオブジェクトを提供する必要があるとされています。だからここでは、それは合法です。const 参照の場合は、一時的なもの (名前のない右辺値) を提供することもできます。

関数は SomeClass への参照を想定していますが、静的に割り当てられた SomeClass 型の変数を渡しています。

SomeClass の非 const インスタンスへの参照を期待しています。それがあなたが提供したものです。そのインスタンスは静的ではなく、スタックに割り当てられているだけです。オブジェクトの割り当ては、オブジェクトの操作方法とは関係がなく、スコープのみが関係します。オブジェクトが割り当てられる方法 (ここのようにスタック上、または new/delete を使用してヒープ上) は、オブジェクトの有効期間のみを示します。constでない限り、静的オブジェクトでさえ関数に渡すことができます。

ここでいくつかの言語概念を混ぜていると思います...

参照はポインタのようなものですよね?

いいえ。

参照は、オブジェクトの「ニックネーム」です。それ以上でもそれ以下でもありません。

わかりました、実際には特別な規則を持つポインタとして実装されていますが、すべての用途に当てはまるわけではありません.コンパイラは自由にそれを実装することができます. 関数属性の場合、ポインターとして実装されることがよくあります。しかし、あなたはそれについて知る必要さえありません。

あなたにとって、それは単なるオブジェクトのニックネームです。

参照をポインターに置き換えると、コンパイラーは文句を言います。このように参照がポインターと異なるのはなぜですか?舞台裏で何が起こっているのでしょうか?

あなたの最初のエラーがあなたにとって物事があいまいになったと思いますか?

于 2011-04-16T22:29:35.697 に答える
0

参照はポインターではありません。パラメータを「値渡し」で渡し、 use-it を使用するだけです。ボンネットの下ではポインタのみが使用されますが、これはボンネットの下だけです。

于 2011-04-16T22:24:16.890 に答える
0

参照はポインターのようなものではなく、他のオブジェクトのエイリアス (新しい名前) です。それが両方を持っている理由の1つです!

このことを考慮:

Someclass a;

Someclass& b = a;
Someclass& c = a;

ここでは、最初に object を作成し、a次に と をb同じcオブジェクトの別の名前とします。新しいものは何も作成されず、2 つの名前が追加されるだけです。

borが関数のパラメーターである場合c、関数内でエイリアス foraが使用可能になり、それを使用して実際のオブジェクトを参照できます。

それはとても簡単です!ポインターを使用する場合&、 、*、またはlike を使用してループをジャンプする必要はありません。->

于 2011-04-17T06:17:49.807 に答える
0

質問にはすでに適切に回答されていますが、「C++ の参照」の関連する言語機能について、さらにいくつかの言葉を共有せずにはいられません。

C プログラマーとして、変数を関数に渡すときに使用できるオプションは 2 つあります。

  1. 変数の値を渡す (新しいコピーを作成する)
  2. ポインタを変数に渡します。

C++ に関して言えば、通常はオブジェクトを扱います。そのオブジェクトで作業する必要がある各関数呼び出しでそのようなオブジェクトをコピーすることは、スペース (および速度) を考慮すると推奨されません。変数アドレスを (ポインター アプローチを介して) 渡すことには利点があり、ポインターを介した変更を避けるためにポインターを 'const' にすることはできますが、ポインターを使用した構文はかなりぎこちなく (ある場所で逆参照演算子を見逃すか、 2 つはデバッグに何時間も費やすことになります!)。

C++ は、「参照」を提供する際に、両方のオプションの最良のものをパッケージ化します。

  1. 参照は、アドレスを渡すのと同じくらい良いと理解できます
  2. 参照を使用するための構文は、変数自体で作業する場合と同じです。
  3. 参照は常に「何か」を指します。したがって、「ヌルポインター」例外はありません。

さらに、参照を「const」にする場合、元の変数への変更は許可されません。

于 2013-01-12T23:27:43.647 に答える