[Notas de estudo básico C++] Referência de gramática C++


citar

conceito de referência

Referência não é uma nova definição de uma variável, mas um alias para uma variável existente.O compilador não abrirá espaço de memória para a variável de referência, ele compartilha o mesmo espaço de memória com a variável que ela referencia.

Por exemplo: Li Kui, conhecido como "Iron Bull" em casa, e "Black Whirlwind"
insira a descrição da imagem aqui
no mundo, que também é a forma de aliasing.


Como usar citações:

tipo e nome da variável de referência (nome do objeto) = entidade de referência;

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

insira a descrição da imagem aqui
Observação: o tipo de referência deve ser do mesmo tipo que a entidade de referência

& neste lugar representa uma referência, não um endereço, um operador tem vários significados, ou seja, sobrecarga de operador.
Observe a distinção:
tipo & significa referência (& após o tipo, como int& b = a;)
& variável significa pegar o endereço (& antes da variável, como int* pa = &a;
) dois.

insira a descrição da imagem aqui


Propriedades de referência

1) Uma referência deve ser inicializada quando for definida
2) Uma variável pode ter várias referências
3) Uma vez que uma entidade é referenciada, ela não pode se referir a outras entidades (o objeto referenciado não pode ser alterado)

#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;
}

insira a descrição da imagem aqui


frequentemente citado

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;
}

Quando a é do tipo const int, significa que a é uma variável constante e a variável constante tem atributos constantes --- o valor não pode ser alterado. Neste momento, se você usar int & para se referir a a, você obterá um alias do tipo int, que é um comum A variável de a pode ser modificada, pode alterar o valor de a, resultando em um conflito que uma variável constante é modificada! Portanto, para evitar esse conflito, ao referenciar uma variável do tipo const int, você deve usar const int& b = a;

Resumo: Quando a referência é alias, a autoridade de acesso variável pode ser reduzida (como const int -> int ), mas não ampliada (como const int -> int ).
As permissões não podem ser ampliadas: variáveis ​​do tipo const não podem ser dadas a aliases de tipos não const As
permissões podem ser reduzidas: ou seja, variáveis ​​de tipos não const podem receber aliases de tipos não const e aliases de tipos const.

Dica: Minificação e ampliação de permissões, apenas para referências e ponteiros

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

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

Observe a distinção:

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; Esta frase é para gerar primeiro uma variável temporária
dupla double& ri = I; É também uma variável temporária que irá gerar primeiro um tipo double, e então a variável temporária é realmente referenciada, e esta variável temporária tem propriedades constantes , então não é possível usar double& diretamente, e não há problema em adicionar const.
insira a descrição da imagem aqui


cenas a serem usadas

1. Faça os parâmetros (①parâmetros de saída ②melhorar a eficiência)

#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;
}

insira a descrição da imagem aqui
P: Isso não significa que a inicialização é necessária ao se referir a uma definição? Não há inicialização aqui?
A: A referência neste local não é uma definição, quando é uma definição? A definição é quando o parâmetro é passado, e a operação de inicialização será executada quando o parâmetro for passado.
insira a descrição da imagem aqui
Claro, isso também pode ser alcançado por ponteiros:

#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;
}

insira a descrição da imagem aqui
2. Faça o valor de retorno (①Melhore a eficiência ②Falarei sobre isso depois)

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

insira a descrição da imagem aqui
Qualquer método de passagem por valor (parâmetro passando por valor, passando por valor e retornando) irá gerar uma cópia da variável temporária. A passagem por referência não.
static altera o ciclo de vida da variável sem modificar os direitos de acesso da variável


Qual é a saída do código a seguir? Por quê?

#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;
}

insira a descrição da imagem aqui
Nota: Se a função retornar fora do escopo da função, se o objeto retornado não tiver sido retornado ao sistema, ele poderá ser retornado por referência e, se tiver retornado ao sistema, deverá ser retornado por valor. (Explique que o retorno por referência não é seguro!)
insira a descrição da imagem aqui
Então, qual é a vantagem de usar o retorno por referência?

Uma variável temporária a menos pode ser criada para melhorar a eficiência do programa (transferência)
Na verdade, existe outra função, que será discutida posteriormente (o retorno de muitas funções da biblioteca também será retornado por referência)


Comparação da eficiência de passagem por valor e de passagem por referência

Com um valor como parâmetro ou tipo de valor de retorno, durante o período de passagem e retorno do parâmetro, a função não passará diretamente o parâmetro real ou retornará a própria variável diretamente, mas passará o parâmetro real ou retornará uma cópia temporária da variável, portanto o valor é usado como parâmetro.Ou o tipo de valor de retorno, a eficiência é muito baixa, especialmente quando o parâmetro ou tipo de valor de retorno é muito grande, a eficiência é ainda menor. Comparação de desempenho
de valores e referências como parâmetros

#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;
}

insira a descrição da imagem aqui


Comparação de desempenho de valor e referência como tipos de valor de retorno

#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;
}

insira a descrição da imagem aqui

Através da comparação do código acima, verifica-se que a eficiência de passar um valor e um ponteiro como parâmetro e retornar um valor é muito diferente.


Diferença entre referência e ponteiro

Em termos de sintaxe, uma referência é um alias, que não possui espaço independente e compartilha o mesmo espaço com sua entidade de referência.

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

insira a descrição da imagem aqui
Na verdade, há espaço na implementação subjacente, porque as referências são implementadas como ponteiros.

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

Vamos dar uma olhada na comparação de código assembly de referências e ponteiros:
insira a descrição da imagem aqui
referências e ponteiros são endereços de armazenamento

Diferenças entre referências e ponteiros:

1. A referência deve ser inicializada quando for definida, e o ponteiro não é obrigatório
. 3. Não
referência NULL, mas há 4. Ponteiros NUL
têm significados diferentes em sizeof: o resultado da referência é o tamanho do tipo de referência, mas o ponteiro é sempre o número de bytes ocupados por o espaço de endereçamento (4 bytes em plataformas de 32 bits)
5. A referência é auto-adicionada, ou seja, a entidade referenciada Aumenta em 1, o ponteiro é auto-adicionado, ou seja, o ponteiro é deslocado para trás pelo tamanho de um tipo.
6. Existem vários níveis de ponteiros, mas não há referências de vários níveis
. 7. A maneira de acessar entidades é diferente. O ponteiro precisa ser desreferenciado explicitamente e o compilador de referência o trata sozinho.
8. Referência Relativamente mais seguro de usar do que ponteiros

Acho que você gosta

Origin blog.csdn.net/QIYICat/article/details/119843659
Recomendado
Clasificación