2

次の例を見てください。、という名前の関数ポインタを作成しs、に設定してf呼び出します。もちろん、これは正常にコンパイルされます。

void f() {}

int main() {

    void (*s)();

    s = f;

    s();

}

しかし、この次の例を見てみましょう。ここではs、「関数参照」として宣言し(いわゆる関数参照)、fインラインに設定します。これも正常にコンパイルされます。

void f() {}

int main() {

    void (&s)() = f;

    s();

}

関数ポインタを作成および初期化するこれら2つの方法の違いは何ですか?参照構文を使用する場合は、「インライン」で初期化する必要がありますfが、「ポインター」構文では、両方の方法で初期化できます。それも説明できますか?それでは、使いやすさの点でそれらの違いは何であるか、そしていつ一方のフォームをもう一方のフォームと比較する必要があるのか​​を説明できますか?

4

5 に答える 5

3

基本的に、呼び出し側には明確な違いはありません。しかし、decl側は間違いなくそうです。ご指摘のとおり、参照は何かを参照するように初期化する必要があります。これにより、それらは「より安全」になりますが、それでも「安全」の保証はありません。

関数ポインタは、関数を指す必要はまったくありません。NULL、または初期化されていない(ガベージを指す)可能性があります。後でいつでも変更できるため、重要ではありません(参照ではできないこと)。

void (*s)();  // uninitialized

また

void (*s)() = NULL; // set to null

以降

void foo() 
{
}

s = foo;

参照を使用してそれらのいずれも実行できません。参照は何かに初期化する必要があり、できれば有効なものに初期化する必要があります。

void (&f)() = foo;   // ok. also references foo().
void (&f)() = *s;    // also ok, but wait, is s valid?? does it have to be??

ただし、ここでも関数参照が安全であるとは限らず、安全であることが保証されています。あなたは確かにこれを行うことができます:

void (*s)();
void (&f)() = *s;

これからコンパイラの警告が表示される場合がありますが(私は「初期化される前に使用されます」)、最終的には関数ではないf「関数」への参照になります。ポインタ内のランダムなスタックのゴミだけです。さらに悪いことに、参照を再割り当てすることはできません。このことは常にゴミを指します。s

于 2012-10-31T21:18:32.007 に答える
2

違いは、他のポインタ/参照の場合と同じです。

参照は初期化する必要があり、後で再割り当てすることはできません。

int i,j;
int &r = i;
r = j; // i = j, not &r == &j

参照は、参照するオブジェクトとは異なるオブジェクトとして扱うことはできません(ポインターは、参照するオブジェクトとは異なるオブジェクトです)。..

int i;
int *p = &i; // &p != &i
int &r = i;  // &r == &i

関数ポインタを使用することは、構文的には参照を使用することと同じように見えますが、これは、関数ポインタを逆参照せずに使用できるようにする特別なルールがあるためです。

于 2012-10-31T21:18:32.710 に答える
2

自分で言ったのですが、違いは、参照を使用する場合は、宣言時にバインドする必要があることです。これにより、参照が常に有効なオブジェクトを参照することが保証されます。もう1つの違いは、参照は宣言された後で再バインドできないため、生涯を通じて1つのオブジェクトのみを参照することです。

それ以外は同じです。私は参照を好む何人かの純粋主義者に会い、ポインターは使用されるべきではないCの痕跡であると言いました。他の人々は、彼らがポインターであるという事実についてより「明示的」であるため、ポインターを好みます。

どちらを使用するかは、ニーズによって異なります。選択する方法は、可能であれば参照を使用することですが、実際に別の関数を指すことができる必要がある場合は、ポインターを使用してください。

于 2012-10-31T21:19:15.317 に答える
0

タイプPへの参照は、タイプPへのconstポインターによく似ています(異なるconst Pへのポインターではありません)。

タイプPが関数型の場合、ほとんどの場合、それらの違いは重要ではありません。&の動作は少し異なります。ポインタを非constポインタに直接割り当てることができ、一方をとる関数はもう一方をとらない場合があります。

タイプPが関数型でない場合、他の多くの違いがあります-演算子=、一時的なものの寿命など。

要するに、答えは「あまりない」です。

于 2012-10-31T21:17:57.997 に答える
0
  1. 関数識別子は関数型の式ですが、暗黙的に関数へのポインター型または関数への参照型に変換されます。したがって、それらは、参照またはポインターのコンストラクターとポインターのoperator=に渡すことができます。

  2. 参照は構文的にインスタンスのように動作するため、参照されたオブジェクトではなく、参照に基づいて動作する方法はありません。そのため、初期化することしかできません。ちなみに、C ++で推奨される構文は、ではなく括弧を使用すること=です。

  3. 可能な場合は参照を使用し、参照を使用できない場合にのみポインターを使用する必要があります。その理由は、参照するために多くのこと(NULLを指す、参照されるオブジェクトの変更、削除など)を実行できないため、コードを読み取るときに探す必要のあることが少なくなるためです。*さらに、いくつかの&文字を保存します。

于 2012-10-31T21:20:14.903 に答える