C++の参照について詳しく解説(参照の特徴、参照とポインタの違い、その他の参照の使い方)

引用

1.はじめに

生活の中で、一部の学生にニックネームを付けることもあります.「張磊」を例にとると、彼を「張三師」と呼ぶことができます.このニックネームを呼ぶと、自然に「張磊」、「張三師」が思い浮かびます.は張磊の別名であり、引用は次の簡単な方法で理解できます。文法レベルでは、引用は別名です

2. C++ でさらに厄介な演算子

* および C++ の & には複数の意味があり、使用条件が異なれば意味も異なります。
*

int *p = &a;   /1.指针
a = a * b;     /2.乘法
*p = 100;      /3.指向

&

int c = a&b;    /1.位运算 转换为二进制
int *p = &a;    /2.取地址
int  a = 100;
int & ar = a;   /3.引用

3. 参照の定義

参照は、変数の新しい定義ではなく、既存の変数のエイリアスです. コンパイラは、参照変数用にメモリ空間を開かず、参照変数と同じメモリ空間を共有します.

形式は次のとおりです

タイプ & 参照変数名 (オブジェクト名) = 参照エンティティ
ここでのスペースはオプションであることに注意してください。

  • 次のように & 記号; の前後にスペースを入れることができます: int & ra=a;
  • & 記号は、次のように型の横にあります。 int& ra=a;
  • & 記号は、次のように参照名の横にあります。

int main()
{
int a =100; \\定义变量名
int b = a;\\将a的值赋给变量
int &c = a;\\引用 将c作为a的别名 c11中成为左值引用
return 0;
}

ここでは a と c という 2 つの名前を持つエンティティに相当し、この空間に新しい空間を開きません。
ここに画像の説明を挿入

4. 引用の特徴

  1. 参照を定義するときに初期化する必要があります
  2. null 参照なし
  3. 二次引用のようなものはありません
  4. 変数は複数の参照を持つことができます (複数のエイリアスを持つ変数と同等であり、可能です)

説明:
int main()
{
int a = 10;
int& b = a;
int& x;
int& y = NULL;
int&& c = a;
}
ここに画像の説明を挿入
要するに:
参照自体は変数ですが、この変数は単なる別の変数とエイリアスであり、メモリ空間を占有せず、ポインタではありません! ただの別名!

5. ポインタと参照の比較

例として swap 関数を使用して、
ポインターを使用して 2 つの整数値を交換してみましょう。

int my _swap (int*ap, int*bp)
{
    
    
	assert(ap != NULL && bp != NULL);
	int tmp = *ap;*ap = *bp;*bp = *ap;
}
int main()
{
    
    
	int x = 10, y = 20;
	my_swap{
    
    &x,&y);
	cout<< "x = " << x << " y = " << y << endl;
	return 0;
}

参照を使用して 2 つのポインターを交換します。

void my_swap (int& a,int& b)
{
    
    
	int tmp = a;a = b;
	b = tmp;
}
int main ()
{
    
    
	int x = 10, y = 20;my_swap(x,y) ;
	cout << " x = " << x<< " y = " << y << endl;
	return 0;
}

仮引数がポインタの場合:最初の文をアサートして空かどうかを判定しなければならず、ポインタを使う場合は注意が必要です:ワイルドポインターヌルポインタ無効化ポインタ.
参照を使用する場合、NULL 参照がなく、null を判断する必要がなく、ポインターよりも安全です。

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
の<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
_

6. 参照とポインタの違い (強調)

1. 文法レベルの違い

  1. 文法規則に関して言えば、ポインター変数はインスタンス (変数またはオブジェクト) のアドレスを格納し、
    参照はインスタンスのエイリアスです。
  2. プログラムはポインタ変数にメモリ領域を割り当てますが、参照にはメモリ領域を割り当てません。
int main()
{
    
    
	int a = 10;
	int* ip = &a;
	int& b = a;  \\b是a的别名 并没有分配新的空间
}
  1. 逆参照とは、ポインタを使用する前に「*」を追加することで、参照を直接使用できます。
int main()
{
    
    
	int a = 10;
	int* ip = &a;
	int& b = a;  
	*ip = 100//对于指针使用加“*”
	b = 200//引用不需要“*”
	
}
  1. ポインター変数の値は、異なるインスタンスのアドレスを格納するために変更できます。
    参照は、定義時に初期化され、後で変更することはできません (他のインスタンスへの参照にすることはできません)。
int main()
{
    
    
	int a = 10,b = 20;
	int* ip = &a;
	ip = &b ;
	int& c = a;
	c = b;   //b的值给c实则是把b的值给a,将a的值改为20
}
  1. ポインター変数の値は空 (NULL、nullptr) にすることができ、null 参照はありません。
  2. ポインタ変数を仮パラメータとして使用する場合は、その有効性をテストする必要があります (NULL と判断する)
    参照は NULL と判断する必要はありません。
  3. ポインター変数で「sizeof」を使用するとポインター変数のサイズが取得され、
    参照変数で「sizeof」を使用すると変数のサイズが取得されます。
int main()
{
    
    
	double dx = 10;
	double* dp = &dx;
	double& a = dx; 
	printf("sizeof(dp):%d\n", sizeof(dp));
	printf("sizeof(a):%d", sizeof(a));
}

操作結果:
ここに画像の説明を挿入

  1. 理論的には、ポインターのレベル数に制限はありませんが、参照のレベルは 1 つだけです。
    つまり、参照への参照はありませんが、ポインターへのポインターは存在できます。

  2. ++参照には、++ポインタとは異なる効果があります。

たとえば、++ 操作に関しては、次のようになります。

int main()
(
	int ar[5] = {
    
     1,2,34,5 };
	int* ip = ar; //数组首元素地址
	int& b = ar[O]; //数组首元素的别名叫b
	++ip;  //由0下标的地址指向1下标的地址
	++b;  //由0下标指向1下标
}

ここに画像の説明を挿入

  1. 参照に対する操作は、参照されるエンティティ (変数またはオブジェクト) に直接反応します。
    ポインター変数に対する操作は、ポインター変数が次のエンティティー (変数またはオブジェクト) のアドレスを指し示すようにします。ポインター変数は、ポイントされたエンティティー (変数またはオブジェクト) の内容を変更するのではありません。
int main()
(
	int ar[5] = {
    
     1,2,34,5 };
	int* ip = ar; //数组首元素地址
	int& b = ar[O]; //数组首元素的别名叫b
	++(*ip); //值由1>>2 
	(*ip)++; //所有表达式结束后 进行++ 
	//有括号 先取ip的值与*结合 然后++为所指之物的++
	int x = *ip++;
	//没有括号 先将ip的值取出 与*结合 把所指之物取出(此时已与*结合完) 然后将ip取出进行++ ++后的值回写给ip 将值存储到x中
	//通过()提高了优先级
}
  1. 関数内のローカル変数またはオブジェクトは、参照またはポインターによって返すことはできません。

    変数の有効期間が関数の影響を受けない場合、アドレスを返すことができます

2. アセンブリ レベルでの相違点

アセンブリ レベルでは、参照はポインターですが、参照は通常のポインターではなく、ポインターの構文スロットであり、通常のポインターと見なすこともできます。

int main()
{
    
    
	int a = 10;
	int* ip = &a;
	int& x = a;
	*ip = 100;
	x = 200;
}

ここに画像の説明を挿入

7. 参考文献のその他の用途

  1. よく引用される:

定数参照は、実際には、通常の変数、定数、またはリテラル定数を参照できるユニバーサル参照です

(1) 通常変数参照

int main()
{
    
    
	int a = 10;
	int & b = a;
    const int& c = a;
    b += 10;
    a += 10;
    c += 10;
    return 0;
}

このエラーの問題の場合: c は変更できないため
ここに画像の説明を挿入
(2) 参照定数

int main()
{
    
    
    int a = 10;
    const int b =20;
    int& x = a;
    int& y = b;  //error 不安全
    const int& y = b; //ok
    const int& z =10; //ok
    return 0;
}

ここに画像の説明を挿入
(3) 文字定数の引用

リテラル定数を参照する場合は2段階に分かれますが、まず実定数リテラルを参照するのではなく、テンポラリを参照するテンポラリを定義します。

int main()
{
    
    
    int a = 10;
    const int& z =10; //ok
    //int tmp =10;
    //const int &z = tmp;
    return 0;
}
  1. 配列参照

配列を参照するときは、配列のサイズがわかっている必要があります

int main()
{
    
    
    int a = 10;
    int b = 10;
    int ar[5] = {
    
     1,2,3,4,5 };
    int& x = ar[0];  //ok
    int(&x)[5] = ar; //ok   没有[5]无法编译通过
  
    return 0;
}
  1. ポインター参照

参照は変数なので、ポインター変数にエイリアスを与えることもできます

int main()
{
    
    
	int a = 100;
	int *p = &a;
	int * &rp = p;
 
	cout << a << endl;
	cout << *p << endl;
	cout << *rp << endl; //这里为什么要将*放在前面,因为p的类型是 int * 作为一个整体哦!!
 
	cout << p << endl;
	cout << rp << endl;
 
	getchar();
	return 0;
}
/*
100
100
100
012FF84C
012FF84C
*/

ここでのポインター変数 p は、その参照 (エイリアス) rp とまったく同じであることがわかりました。ただし、参照の目的はポインターの目的と似ているため、通常、ポインターに別名を付ける必要はありません。

おすすめ

転載: blog.csdn.net/weixin_56935264/article/details/124669712