[Data structure] About c++ references

Reprinted source: http://www.cnblogs.com/xiaofengkang/


The big guy's summary: One of the benefits of quoting is that no copy is generated in memory when the function is called.

Quote summary

(1) In the use of reference, it is meaningless to simply give a variable an alias. The purpose of reference is mainly used to solve the problem of unsatisfactory transfer efficiency and space of large blocks of data or objects in the transfer of function parameters .
(2) Passing function parameters by reference can ensure that no copy is generated during parameter passing, which improves the efficiency of the transfer, and the use of const ensures the safety of reference transfer.
(3) The difference between reference and pointer
<1> After a pointer points to an object through a pointer variable, it indirectly operates on the variable it points to. The use of pointers in the program makes the program less readable;
<2> The reference itself is the alias of the target variable, and the operation of the reference is the operation of the target variable.
(4) Timing of using citations. The flow operators << and >>, the return value of the assignment operator =, the parameters of the copy constructor, the parameter of the assignment operator =, and other situations are all recommended to use references.

A reference is an alias for a variable (target), and the operation on the reference is exactly the same as the direct operation on the variable.

Referenced declaration method
类型标识符 &引用名=目标变量名;

【例1】:
int a;  
int &ra=a;  //定义引用ra,它是变量a的引用,即别名

(1) & here is not for address calculation, but for identification.
(2) The type identifier refers to the type of the target variable.
(3) When declaring a reference, it must be initialized at the same time.
(4) After the reference is declared, it is equivalent to the target variable name has two names, namely the original name of the target and the reference name, and the reference name cannot be used as an alias for other variable names.

ra=1; 	//等价于 a=1; 

(5) Declaring a reference is not a new definition of a variable, it only means that the reference name is an alias of the target variable name, it is not a data type itself, so the reference itself does not occupy the storage unit, and the system does not allocate the reference Storage unit. Therefore: to seek the address of the reference is to seek the address of the target variable. &ra is equal to &a.
(6) The reference of the array cannot be established. Because an array is a collection of several elements, it is impossible to create an alias for an array.
(7) A reference to a reference cannot be established, and a pointer to a reference cannot be established. Because reference is not a data type! ! So there are no references to references, no pointers to references.

【例如】:
int n;
int &&r=n;//错误,编译系统把"int &"看成一体,把"&r"看成一体,即建立了引用的引用,引用的对象应当是某种数据类型的变量
int &*p=n;//错误,编译系统把"int &"看成一体,把" *p "看成一体,即建立了指向引用的指针,指针只能指向某种数据类型的变量

(8) It is worth mentioning that you can create pointer references

【例如】:
int *p;
int *&q=p;//正确,编译系统把" int * "看成一体,把"&q"看成一体,即建立指针p的引用,亦即给指针p起别名q。

Reference application

1. Reference as a parameter

An important role of reference is as a function parameter. In the previous C language, function parameter transfer was value transfer. If a large block of data is passed as a parameter, the solution used is often a pointer, because this can avoid pushing the entire block of data on the stack and improve the efficiency of the program. But now (in C++) an equally efficient option (and a necessary option in some special cases) has been added, which is reference.

【例2】:
void swap(int &p1,  int &p2) {
    
    //此处函数的形参p1, p2都是引用 
	int p;
	p=p1;
	p1=p2;
	p2=p;
} 

In order to call the function in the program, the call point of the corresponding main calling function can be called directly with the variable as the actual parameter, without any special requirements for the actual parameter variable.
For example, corresponding to the swap function defined above, the corresponding main calling function can be written as:

main(){
    
     
 int a,b;
 cin>>a>>b; 			//输入a,b两变量的值
 swap(a,b); 			//直接以变量a和b作为实参调用swap函数 
 cout<<a<< ' ' <<b; 	//输出结果 
}
上述程序运行时,如果输入数据10 20并回车后,则输出结果为20 10。

由【例2】可看出:
(1) The effect of passing a reference to a function is the same as passing a pointer. At this time, the formal parameter of the called function becomes an alias of the actual parameter variable or object in the original calling function to use, so the operation of the formal parameter variable in the called function is to its corresponding target object (in the calling function). In the call function).
(2) The use of reference to pass the parameters of the function does not produce a copy of the actual parameters in the memory, it is a direct operation on the actual parameters; and the use of general variables to pass the parameters of the function, when a function call occurs, it is necessary to allocate storage to the formal parameters Unit, the formal parameter variable is a copy of the actual parameter variable; if the object is passed, the copy constructor will also be called. Therefore, when the data passed by the parameter is large, the efficiency and the space occupied by the reference are better than the general variable.
(3) Although the use of pointers as function parameters can also achieve the effect of using references, in the called function, storage units must also be allocated to formal parameters, and the form of "*pointer variable name" needs to be repeatedly used for calculations. This is prone to errors and poor readability of the program; on the other hand, at the call point of the calling function, the address of the variable must be used as the actual parameter. The citation is easier to use and clearer.

void fun(int * a,int * b){
    
    
	int t = (*a);
	*a = *b;
	*b = t;
}

The corresponding key function is:

int main(){
    
    
	int i = 1,j = 2;
	fun(&i,&j);
	cout<<i<<" "<<j<<endl;
	return 0;
}

If you want to use references to improve the efficiency of the program, but also to protect the data passed to the function from being changed in the function, you should use constant references.

2, often cited

Often quoted declaration

const 类型标识符 &引用名=目标变量名;

The reference declared in this way cannot modify the value of the target variable by reference, so that the target of the reference becomes const, which achieves the safety of the reference.

【例3】: 
int a ;
const int &ra=a;
ra=1;		//错误,不能通过引用对目标变量的值进行修改
a=1;		//正确 

This is not only to make the code more robust, but also has other needs.

【例4】:假设有如下函数声明:
string foo();
void bar(string & s);

Then the following expression will be illegal:

bar(foo());
bar("hello world"); 

The reason is that both foo() and "hello world" strings will produce a temporary object, and in C++, these temporary objects are of const type. Therefore, the above expression is an attempt to convert a const type object to a non-const type, which is illegal.

引用型参数应该在能被定义为const的情况下,尽量定义为const

3. Reference as return value

To return the function value by reference, the function definition should be in the following format: Description: (1) Return the function value by reference, and add & before the function name when defining the function. (2) The biggest advantage of returning a function value by reference is that, No copy of the returned value is made in memory.
类型标识符 &函数名(形参列表及类型说明)
{函数体}



【例5】: 以下程序中定义了一个普通的函数fn1(它用返回值的方法返回函数值),另外一个函数fn2,它以引用的方法返回函数值。

#include <iostream.h>

float  temp;				//定义全局变量temp
float  fn1(float r);		//声明函数fn1
float  &fn2(float r);		//声明函数fn2
float  fn1(float r);		//声明函数fn1

float  fn1(float r){
    
     		//定义函数fn1,它以返回值的方法返回函数值
	temp=(float)(r*r*3.14); 
	return temp; 
}

float &fn2(float r){
    
     		//定义函数fn2,它以引用方式返回函数值
	temp=(float)(r*r*3.14); 
	return temp;
}

void main() {
    
     				//主函数
	float a=fn1(10.0); 		//第1种情况,系统生成要返回值的副本(即临时变量)
	float &b=fn1(10.0); 	//第2种情况,可能会出错(不同 C++系统有不同规定)
 //不能从被调函数中返回一个临时变量或局部变量的引用
	float c=fn2(10.0); 		//第3种情况,系统不生成返回值的副本
 //可以从被调函数中返回一个全局变量的引用
	float &d=fn2(10.0); 	//第4种情况,系统不生成返回值的副本
 //可以从被调函数中返回一个全局变量的引用
	cout<<a<<c<<d;
} 

引用作为返回值,必须遵守以下规则:
(1) References to local variables cannot be returned. This article can refer to Item 31 of Effective C++[1]. The main reason is that local variables will be destroyed after the function returns, so the returned reference becomes a "non-referred" reference, and the program will enter an unknown state.
(2) A reference to the memory allocated by new within the function cannot be returned. This article can refer to Item 31 of Effective C++[1]. Although there is no passive destruction of local variables, but for this situation (returning a reference to the new allocated memory inside the function), it faces other embarrassing situations. For example, if the reference returned by the function only appears as a temporary variable, but is not assigned to an actual variable, then the space pointed to by this reference (allocated by new) cannot be released, causing a memory leak.
(3) References to class members can be returned, but const is best. This principle can refer to Item 30 of Effective C++[1]. The main reason is that when the attributes of an object are associated with a certain business rule, its assignment is often related to some other attributes or the state of the object, so it is necessary to encapsulate the assignment operation in a business rule. If other objects can obtain a non-constant reference (or pointer) of the attribute, then the simple assignment of the attribute will destroy the integrity of the business rules.
(4) Overloading of references and some operators:
Stream operators << and >>, these two operators are often expected to be used consecutively, for example: cout << "hello" << endl; Therefore, the return value of these two operators should be one and still support these two operations The stream reference of the symbol. Other optional solutions include: returning a stream object and returning a stream object pointer. But for returning a stream object, the program must reconstruct (copy) a new stream object, that is to say, the two consecutive << operators are actually for different objects! This is unacceptable. For returning a stream pointer, the << operator cannot be used continuously. Therefore, returning a stream object reference is the only option. This only choice is very important. It illustrates the importance and irreplaceability of references. Perhaps this is the reason why the concept of reference is introduced in the C++ language. Assignment operator =. This operator, like the stream operator, can be used continuously, for example: x = j = 10; or (x=10)=100; the return value of the assignment operator must be an lvalue so that it can be assigned. Therefore, reference becomes the only return value option for this operator.

【例6】 测试用返回引用的函数值作为赋值表达式的左值。
#i nclude <iostream.h>
int &put(int n);
int vals[10];
int error=-1;
void main(){
    
    
put(0)=10;  //以put(0)函数值作为左值,等价于vals[0]=10; 
put(9)=20;  //以put(9)函数值作为左值,等价于vals[9]=10; 
cout<<vals[0]; 
cout<<vals[9];
}


int &put(int n){
    
    
	if (n>=0 && n<=9 )
		return vals[n]; 
	else 
		cout<<"subscript error"; return error;
}

(5) In some other operators, never return references: +-* / Four arithmetic operators. They cannot return references, Item 23 of Effective C++ [1] discusses this issue in detail. The main reason is that these four operators have no side effects. Therefore, they must construct an object as the return value. The optional solutions include: return an object, return a reference to a local variable, return a reference to an object allocated by new, and return A static object reference. According to the aforementioned three rules of reference as return value, the second and third options were both rejected. References to static objects also cause errors because ((a+b) == (c+d)) will always be true. So the only option left is to return an object.

4. Quoting and polymorphism

Reference is another means besides pointers that can produce polymorphic effects. This means that a reference to a base class can point to an instance of its derived class.

【例7】: 
class A;
class B:public A{
    
    ……};
B b;
A &Ref = b;  // 用派生类对象初始化基类对象的引用

Ref can only be used to access members of the derived class object inherited from the base class, and the base class reference points to the derived class. If a virtual function is defined in class A and the virtual function is rewritten in class B, polymorphic effects can be produced through Ref.

Guess you like

Origin blog.csdn.net/qq_44714521/article/details/107006806