私はCの男で、C++コードを理解しようとしています。次の関数宣言があります。
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
関数シグネチャは、同等のCとどのように異なりますか:
int foo(const char *myname)
string *myname
とstring &myname
の使用に違いはありますか?ポインターを示すためのC++の&
とCの*
の違いは何ですか?
同様に:
const string &GetMethodName() { ... }
ここで&
は何をしていますか? CとC++で&
が異なる方法で使用される方法を説明するWebサイトはありますか?
「&」は、オブジェクトへのポインタの代わりに参照を示します(あなたの場合、定数参照)。
次のような機能を持つことの利点
foo(string const& myname)
以上
foo(string const* myname)
前者の場合、C++はNULL参照を許可しないため、mynameがnullでないことが保証されます。参照渡しであるため、オブジェクトをコピーすることはありません。ポインタを渡す場合と同じです。
2番目の例:
const string &GetMethodName() { ... }
たとえば、メンバー変数への定数参照を返すことができますか。これは、コピーが返されたくない場合に便利です。また、返される値がnullでないことが保証されます。例として、次の例では、読み取り専用アクセスを直接許可しています。
class A
{
public:
int bar() const {return someValue;}
//Big, expensive to copy class
}
class B
{
public:
A const& getA() { return mA;}
private:
A mA;
}
void someFunction()
{
B b = B();
//Access A, ability to call const functions on A
//No need to check for null, since reference is guaranteed to be valid.
int value = b.getA().bar();
}
もちろん、無効な参照を返さないように注意する必要があります。コンパイラーは、以下を喜んでコンパイルします(警告レベルと警告の扱い方によって異なります)
int const& foo()
{
int a;
//This is very bad, returning reference to something on the stack. This will
//crash at runtime.
return a;
}
基本的に、参照を返すものが実際に有効であることを保証するのはあなたの責任です。
ここに、 &
は演算子として使用されません。関数または変数の宣言の一部として、&
は参照を示します。 C++ FAQ Liteにはかなり気の利いた リファレンスの章 があります。
string *とstring&は、いくつかの点で異なります。まず、ポインターはデータのアドレス位置を指します。参照はデータを指します。次の機能がある場合:
int foo(string *param1);
関数宣言をチェックインして、param1が有効な場所を指していることを確認する必要があります。比較的:
int foo(string ¶m1);
ここで、ポイントされたデータが有効であることを確認するのは呼び出し元の責任です。たとえば、上記の2番目の関数のように、「NULL」値を渡すことはできません。
2番目の質問に関して、メソッドの戻り値が参照されることについて、次の3つの関数を検討してください。
string &foo();
string *foo();
string foo();
最初のケースでは、データへの参照を返します。関数宣言が次のようになった場合:
string &foo()
{
string localString = "Hello!";
return localString;
}
その関数のスタックで初期化された文字列への参照を返すため、おそらくいくつかのコンパイラエラーが発生します。関数が戻ると、そのデータの場所は無効になります。通常、クラスメンバーまたはそのようなものへの参照を返します。
上記の2番目の関数は、実際のメモリにポインタを返すため、同じままです。ただし、NULLポインターを確認する必要があります。
最後に、3番目のケースでは、返されたデータが呼び出し元の戻り値にコピーされます。あなたの関数が次のようなものだった場合:
string foo()
{
string localString = "Hello!";
return localString;
}
文字列「Hello」はその関数の戻り値にコピーされ、呼び出し元のメモリ空間でアクセスできるため、大丈夫です。
C++の&(参照)演算子を見る1つの方法は、単なるポインターへの構文糖です。たとえば、次はroughlyと同等です。
void foo(int &x)
{
x = x + 1;
}
void foo(int *x)
{
*x = *x + 1;
}
より便利なのは、クラスを扱っている場合で、メソッドがx-> bar()からx.bar()に変わります。
大まかにと言った理由は、参照を使用すると、ポインターを処理するときに発生する問題の一部から保護するために、参照でできることに対して追加のコンパイル時制限が課せられるためです。たとえば、誤ってポインターを変更したり、渡された特異なオブジェクトを参照する以外の方法でポインターを使用したりすることはできません。
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(&number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
*p=*p+100;
return(*p);
}
これはいくつかの点で無効なコードです。 g ++で実行すると、以下が得られます。
crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’
コードの有効なバージョンは次のとおりです。
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
p=p+100;
return p;
}
ここで起こっているのは、関数に「そのまま」変数を渡しているということです。これはおおよそ次と同等です。
int add(int *p)
{
*p=*p+100;
return *p;
}
ただし、関数への参照を渡すと、参照を使用したポインター演算などを実行できなくなります。例えば:
int add(int &p)
{
*p=*p+100;
return p;
}
無効です。
must参照へのポインタを使用する場合は、明示的に行う必要があります。
int add(int &p)
{
int* i = &p;
i=i+100L;
return *i;
}
テスト実行では、(予想どおり)ジャンク出力が得られます:
The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
関数は文字列への定数referenceを宣言します:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
参照にはいくつかの特別なプロパティがあり、多くの点でポインタのより安全な代替となります。
関数シグネチャは、同等のCとどのように異なりますか:
int foo(const char *myname)
最初のオブジェクトはオブジェクトを直接参照しますが、const char*
はデータを指すために逆参照する必要があるため、いくつかの違いがあります。
文字列* mynameと文字列&mynameの使用に違いはありますか?
パラメータを扱う際の主な違いは、&myname
を逆参照する必要がないことです。より簡単な例は次のとおりです。
int add_ptr(int *x, int* y)
{
return *x + *y;
}
int add_ref(int &x, int &y)
{
return x + y;
}
まったく同じことを行います。この場合の唯一の違いは、渡される変数を直接参照するため、x
とy
を間接参照する必要がないことです。
const string &GetMethodName() { ... }
ここで何をしていますか? CとC++で&が異なる方法で使用される方法を説明するWebサイトはありますか?
これは、文字列への定数参照を返します。そのため、呼び出し元は返された変数に直接アクセスできますが、読み取り専用の意味でのみです。これは、余分なメモリを割り当てずに文字列データメンバーを返すために時々使用されます。
参照にはいくつかの微妙な点があります。詳細については、 C++ FAQ References) を参照してください。
このコンテキストでは、&
により、関数は参照によりstringname
を取得します。参照とポインターの違いは次のとおりです。
NULL
は参照に対する有効な値ではないため、コンパイラエラーが発生します。したがって、一般に、C++関数で出力パラメーター(または一般的なポインター/参照)を使用する場合、そのパラメーターにNULL値を渡すことを許可する必要がある場合は、ポインター(またはスマートポインター、できれば)を使用します。 NULL値を渡すことがその関数にとって意味がない場合は、参照を使用します。b = 4;
と書いてa
の値を変更できないように。参照の値は、参照したものの値です。