[C++基本学習ノート]C++文法リファレンス


引用

リファレンスコンセプト

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

例:自宅では「IronBull」として知られているLi Kui、
ここに画像の説明を挿入
世界では「Black Whirlwind」、これはエイリアシングの方法でもあります。


引用の使用方法:

タイプと参照変数名(オブジェクト名)=参照エンティティ;

#include<iostream>
using namespace std;
void TestRef()
{
    
    
	int a = 10;
	int& ra = a;//定义引用类型
	cout << a << endl;
	cout << ra << endl;
}
int main()
{
    
    
	TestRef();
	return 0;
}

ここに画像の説明を挿入
注:参照タイプは、参照エンティティと同じタイプである必要があります

&この場所は、アドレスではなく参照を表します。演算子には複数の意味があります。つまり、演算子のオーバーロードです。
区別に注意してください:
type&は参照(int&b = a;などの型の後の&) &variableはアドレスを取ること
を意味します(int * pa =&a;などの変数の前の&)
2。

ここに画像の説明を挿入


参照プロパティ

1)参照は、定義時に初期化する必要があります
2)変数は複数の参照を持つことができます
3)エンティティが参照されると、他のエンティティを参照できなくなります(参照されるオブジェクトは変更できません)

#include<iostream>
using namespace std;
void TestRef()
{
    
    
	int a = 10;
	int b = 20;
	//int& ra;//该条语句编译时会报错
	int& ra = a;//定义引用变量的时候就需要给其赋初始值
	int& rra = a;//一个变量可以有多个引用
	ra = b;//不能更改引用对象,这句实际上是将b的值赋值给ra

	cout << a << endl;
	cout << ra << endl;
	cout << rra << endl;
}
int main()
{
    
    
	TestRef();
	return 0;
}

ここに画像の説明を挿入


よく引用される

void TestConstRef()
{
    
    
	const int a = 10;
	//int& ra = a;//该语句编译时会出错,a为常量
	const int& ra = a;
	//int& b = 10;//该语句编译时会出错,b为常量
	const int& b = 10;
	double d = 12.34;
	//int& rd = d;l/该语句编译时会出错,类型不同
	const int& rd = d;
}

aがconstint型の場合、aは定数変数であり、定数変数は定数属性を持っていることを意味します---値は変更できません。このとき、int&を使用してaを参照すると、次のようになります。共通のint型のエイリアスaの変数は変更できますが、aの値が変更される可能性があり、定数変数が変更されるという競合が発生する可能性があります。したがって、この競合を回避するには、const int型の変数を参照するときに、const int&b=a;を使用する必要があります。

概要:参照がエイリアス化されている場合、可変アクセス権限を狭めることはできますが(const int-> intなど)、拡大することはできません(const int-> intなど)。
権限を拡大することはできません:const型の変数を非const型のエイリアスに与えることはできません。
権限を減らすことができます:つまり、非const型の変数に、非const型のエイリアスとconst型のエイリアスを与えることができます。

ヒント:アクセス許可の縮小と拡大、参照とポインターのみ

const int a = 10;
int* p = &a;//这种不行,权限的放大
const int* pa = &a;//需要这种形式

int c = 1;
const int* pc = &c;//可以,属于权限的缩小

違いに注意してください:

const int a = 10;
int& b = a;//这种是不行的,b是a的别名

const int x = 10;
int y = x;//这种是可以的,y和x没什么关系
//这种是不受影响的
#include<iostream>
using namespace std;
int main()
{
    
    
	int i = 1;
	double d = i;//隐式类型转换
	double& ri = i;//可以这样取别名吗? error
	const double& rri = i;//这样呢?ok
	return 0;
}

double d = I;この文は、最初にdouble一時変数を生成します
double&ri = I;これは、最初にdouble型を生成する一時変数でもあり、次に一時変数が実際に参照され、この一時変数には定数プロパティがあります、したがって、double&を直接使用することはできず、constを追加してもかまいません。
ここに画像の説明を挿入


使用するシーン

1.パラメータを作成します(①出力パラメータ②効率を向上させます)

#include<iostream>
using namespace std;
void Swap(int& left, int& right)
{
    
    
	int temp = left;
	left = right;
	right = temp;
}

int main()
{
    
    
	int a = 1;
	int b = 2;
	Swap(a, b);
	cout << a << " " << b << endl;
	return 0;
}

ここに画像の説明を挿入
Q:定義を参照するときに初期化が必要という意味ではありませんか?ここに初期化はありませんか?
A:この場所での参照は定義ではありませんが、いつ定義されますか?定義はパラメーターが渡されたときであり、初期化操作はパラメーターが渡されたときに実行されます。
ここに画像の説明を挿入
もちろん、これはポインタによっても達成できます。

#include<iostream>
using namespace std;
void Swap(int* pa, int* pb)
{
    
    
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
int main()
{
    
    
	int a = 1;
	int b = 2;
	Swap(&a, &b);
	cout << a << " " << b << endl;
	return 0;
}

ここに画像の説明を挿入
2.戻り値を実行します(①効率の向上②後で説明します)

int& Count()
{
    
    
	static int n = 0;
	n++;
	// ...
	return n;
}

ここに画像の説明を挿入
値を渡す方法(パラメーターを値で渡す、値を渡す、返す)は、一時変数のコピーを生成します。参照渡しはしません。
staticは、変数のアクセス権を変更せずに、変数のライフサイクルを変更します


次のコードの出力は何ですか?なぜですか?

#include<iostream>
using namespace std;
int& Add(int a, int b)
{
    
    
	int c = a + b;
	return c;
}
int main()
{
    
    
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1,2) is : " << ret << endl;
	return 0;
}

ここに画像の説明を挿入
注:関数が関数スコープから戻った場合、返されたオブジェクトがシステムに返されていない場合は参照によって返すことができ、システムに返された場合は値によって返す必要があります。(参照による返品は安全ではないことを説明してください!)
ここに画像の説明を挿入
では、参照による返品を使用する利点は何ですか?

プログラムの効率を向上させるために、一時変数を1つ少なくすることができます(転送)
。実際、後で説明する別の関数があります(多くのライブラリ関数の戻り値も参照によって返されます)


値渡しと参照渡しの効率の比較

値をパラメーターまたは戻り値の型として使用すると、パラメーターの受け渡しおよび戻り期間中に、関数は実際のパラメーターを直接渡したり、変数自体を直接返したりするのではなく、実際のパラメーターを渡すか、変数の一時コピーを返します。値はパラメータとして使用されます。または戻り値タイプの場合、効率は非常に低くなります。特に、パラメータまたは戻り値タイプが非常に大きい場合、効率はさらに低くなります。
パラメータとしての値と参照のパフォーマンス比較

#include<iostream>
using namespace std;
#include <time.h>
struct A
{
    
    
	int a[10000];
};
void TestFunc1(A a)
{
    
    
}
void TestFunc2(A& a)
{
    
    
}
void TestRefAndValue()
{
    
    
	A a;
	//以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < 1000000; ++i)
		TestFunc1(a);
	size_t end1 = clock();

	//以引用作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 1000000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	//分别计算两个函数运行结束后的时间
	cout << "TestFunc1(A)-time : " << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time: " << end2 - begin2 << endl;
}
int main()
{
    
    
	TestRefAndValue();
	return 0;
}

ここに画像の説明を挿入


戻り値型としての値と参照のパフォーマンス比較

#include<iostream>
using namespace std;
#include <time.h>
struct A
{
    
    
	int a[10000];
};
A a;

A TestFunc1()
{
    
    
	return a;
}
A& TestFunc2()
{
    
    
	return a;
}
void TestRefAndValue()
{
    
    
	A a;
	//以值作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < 1000000; ++i)
		TestFunc1();
	size_t end1 = clock();

	//以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < 1000000; ++i)
		TestFunc2();
	size_t end2 = clock();

	//分别计算两个函数运行结束后的时间
	cout << "TestFunc1()-time : " << end1 - begin1 << endl;
	cout << "TestFunc2()-time: " << end2 - begin2 << endl;
}
int main()
{
    
    
	TestRefAndValue();
	return 0;
}

ここに画像の説明を挿入

上記のコードを比較すると、値とポインターをパラメーターとして渡し、値を返す効率が大きく異なることがわかります。


参照とポインタの違い

構文に関しては、参照はエイリアスであり、独立したスペースがなく、参照エンティティと同じスペースを共有します。

#include<iostream>
using namespace std;
int main()
{
    
    
	int a = 10; int& ra = a;
	cout << "&a = " << &a << endl;
	cout << "&ra = " << &ra << endl;
	return 0;
}

ここに画像の説明を挿入
参照はポインタとして実装されているため、基になる実装には実際にはスペースがあります。

#include<iostream>
using namespace std;
int main()
{
    
    
	int a = 10;
	int& b = a;
	int* p = &a;
	return 0;
}

参照とポインターのアセンブリコード比較を見てみましょう。
ここに画像の説明を挿入
参照とポインターはストレージアドレスです。

参照とポインタの違い:

1.参照は定義時に初期化する必要があり、ポインタは必要ありません
。2.参照が初期化時にエンティティを参照した後は、他のエンティティを参照できず、ポインタは次の任意のエンティティを指すことができます。いつでも同じタイプ
。3。NULL参照はありませんが、4があります。NULポインター
のsizeofの意味は異なります。参照結果は参照タイプのサイズですが、ポインターは常に占有されるバイト数です。アドレス空間(32ビットプラットフォームでは4バイト)
5。参照は自己追加されます。つまり、参照されるエンティティは1増加します。ポインタは自己追加されます。つまり、ポインタは次のサイズだけ後方にオフセットされます。タイプ。6。
ポインターには複数のレベルがありますが、マルチレベルの参照はありません
。7.エンティティにアクセスする方法が異なります。ポインターを明示的に逆参照する必要があり、参照コンパイラーがそれを単独で処理します
。8。参照ポインタよりも比較的安全に使用できます

おすすめ

転載: blog.csdn.net/QIYICat/article/details/119843659