C ++ basics: function overloading, reference, inline function, auto, range for loop


Function overloading

C ++ introduced a new feature, function overloading.

Under the same scope, for the same function name, the parameters of the function are different, the order of different types of parameters is different, and the number of parameters is different, all can form a function overload (different parameter names, different return values ​​do not form overload )

Function overloading is mainly used to handle data with the same function but different types.

E.g

int test(int i, int j)
{
	cout << "test" << endl;
}

int test(double i, int j)
{
	cout << "test" << endl;
}

int test(double i, int j, int k)
{
	cout << "test" << endl;
}

Why does C ++ support overloading and C language does not?

Because the processing of windows is more complicated, it is more intuitive to use gcc and g ++ under linux.

First of all, we must know that when the linker sees that a function is called, it will go to the symbol table to find the corresponding function name, to obtain the address of the function, and then link together

First look at how the C language is processed.
Insert picture description here
Insert picture description here
Through disassembly, we can see that the C language does not process the function name. That is to say, no matter how many parameters we have, the types of parameters, and the order of the parameters, we only recognize the function. Name, if there is a second one with the same function name, it is considered redefinition.

Let's look at C ++ again.
Insert picture description here
Insert picture description here
Here you can see that C ++ has processed the function name. The function starts with _Z4, then the function name, and finally the abbreviation of all parameters.
_Z is the prefix of all functions, 4 is the number of characters in the function name, for example, the first _Z4testii represents the function name test, with four characters, the parameters are ii.

This is why the return value is different and the parameter name does not constitute an overload. C ++ uses this function name modification rule to implement function overloading.

external “C”

Sometimes we are using C ++. For some functions that want to be compiled in C style, just add extern “C” before the function, which means to tell the compiler to compile the function according to C language rules.

Insert picture description here


Quote

Quoted concepts

Reference is to give another name to an object. You can use this alias to operate on the original object. At the same time, the compiler will not open up space for the reference variable. It shares a space with the object it refers to.

Usage: type & reference object name = reference entity

int main()
{
	int i = 5;
	int& j = i;
	cout << i << ' ' << j << endl;
	j = 8;
	cout << i << ' ' << j << endl;

	return 0;
}

Insert picture description here

Referenced features

  1. The reference must be initialized when it is defined (because the reference is an alias for an object, it must be initialized)
  2. An object can have multiple references
  3. Once you reference an entity, you can no longer refer to other entities (a bit like the top-level const of a pointer)

Often quoted

int main ()

{
	const int i = 5;
	int& j = i;
	//错误的
	const int & k = i;
	正确的
}

The constant i is referenced here, because i is a constant, so its value cannot be modified, so when we use a normal reference, we will enlarge its permissions, resulting in the ability to modify i through j, this is Unreasonable, so the compiler will report an error. Only use constant references

int main()
{
	int x = 6;
	const int & y = x;
}

At the same time, we use a constant reference to refer to this x, x can be modified, and y can not be modified, so that the permissions shrink and become read-only, so this is feasible.

Cross-reference

int main()
{
	double x = 3.14;
	int& y = x;
	//错误的
	
	const int& z = x;
	//正确的
	return 0;
}

Here we use y and z to refer to x, but the compiler will prompt that y reports an error, z is legal, and it is also a cross-type. Why is this the case?

Because when the type is different, a temporary quantity will be used to refer to x, and then the temporary quantity will be referenced.

int main()
{
	double x = 3.14;
	int& y = x;
	/*
		等价于
		const int &temp = x;
		int &y = temp;
	*/

	const int& y = x;
	/*
		等价于
		const int &temp = x;
		const int &z = temp;
	*/

	return 0;
}

If it is an ordinary reference, then we are actually referring to temp, but we want to modify x, but this is not possible, because the temporary quantity is constant, so this behavior is illegal.

If it is a constant reference, it means that we will not modify x, so even if the reference is actually a temporary quantity temp, this behavior is legal

Cited usage scenarios

  1. As parameter
struct A
{
	int arr[1000000];
};

void test(A& s1)
{

}

Suppose we have a super large structure. If we pass the structure directly, a temporary variable will be generated to copy the structure into the formal parameters. This is a huge overhead, but if we use references, Only an alias is passed, but the same thing needs to be noted as above. Because the temporary quantity is constant, if we want to pass a constant, we must add const before the reference.

  1. As return value
> int& Add(int a, int b) 
{
	int c = a + b;
	return c;
}

int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << ret << endl;
	return 0;
}

For such a code, we may first think that ret will be 3
Insert picture description here
but it is actually 7.

Because we return a reference to c, but c only exists in the stack frame at the time of the call. After the call is completed, the stack frame will be destroyed. Although the data will not be cleared after the destruction, but the access to the area The permission will be released, it may be used by the next call function, or it may be used by an operation, so this is an extremely unsafe behavior. If we want to return a reference, we must Make sure that the object will still exist in the scope of the function.
The 7 above is the value of c modified after the second call.

Therefore, if you need to quote as a return value, you must ensure that the function scope is out, and the returned object is not returned to the system and still exists.

When a value is used as a parameter or a return value, a temporary copy of the original variable is passed or returned when passing parameters and returning. This efficiency is very low, especially when the data is particularly large, but if you use a reference as With parameters, there will be no such problems.

References and pointers

Earlier we said that a reference is an alias for an object. There is no separate space, and it shares a space with the entity it refers to, but this is only a grammatical concept . At the same time, we found that the reference is actually similar to the pointer, it is more like a top-level const pointer, so we can enter the disassembly to see if there is a relationship between them

int main()
{
	int x = 5;
	int& y = x;
	int* z = &x;

	return 0;
}

Insert picture description here
Under disassembly, we can see that the implementation of pointers and references in assembly is exactly the same.

So we can draw a conclusion that references are implemented according to pointers, and new functions are encapsulated on the basis of pointers

Differences between references and pointers:

  1. References must be initialized when they are defined, pointers are not required
  2. After a reference refers to an entity during initialization, it can no longer refer to other entities, and the pointer can point to any entity of the same type at any time
  3. No NULL reference, but NULL pointer
  4. The meaning is different in sizeof: the reference result is the size of the reference type, but the pointer is always the number of bytes occupied by the address space (4 bytes under 32-bit platforms)
  5. The referenced self-adding refers to the referenced entity incremented by 1, and the pointer self-adding refers to the pointer offset by a type size
  6. There are multilevel pointers, but no multilevel references
  7. The way to access the entity is different, the pointer needs to be explicitly dereferenced, and the reference compiler handles it
  8. References are relatively safer to use than pointers

Inline function

The function modified with the inline keyword is an inline function. At compile time, the compiler will expand the code of the function where the inline function is called, minus the overhead of function stacking, and improve the efficiency of the program.
Insert picture description here
For example, such a simple Code
If we call it directly
Insert picture description here
in the assembly, we can see that it will create a new stack frame, push the parameters 3 and 4 onto the stack, and then calculate and return the result
. If you add inline in front of the function to make it inline When you
Insert picture description here
look at the function at this time, you will find that it directly expands the code of the function directly at the call, and does not create a new stack frame.

Characteristics of inline functions

  • Inline functions are a method of swapping space for time, which saves the overhead of creating stack frames and pushing stacks. However, the code is very complicated and functions with loops or recursion are not suitable as inline functions, even if they are declared as The inline function compiler will also ignore it automatically.
  • Inline functions cannot be declared and defined separately, because once they are declared as inline functions, they will be directly expanded when they are called. Without the address of the function, it cannot be linked to the defined part.

It is worth mentioning that inline functions are somewhat similar to macro functions in C. Although the performance of macros is good, because macros lack type safety checks and cannot be debugged (the macro replacement was performed in the preprocessing stage), in C ++ Medium macro functions are replaced by inline functions , and macro constant definitions are replaced by const.


auto

When programming, we often need to assign the value of the expression to a variable, but sometimes we do n’t know what the type of the expression is. To solve this problem, C ++ 11 introduced the auto type specifier, which can be used to make the compiler Instead of analyzing the type of expression .

Because auto needs to let the compiler infer the type of the variable through the initial value, so auto must have an initial value.

int main()
{
	auto i = 2.7;
	cout << i <<"的类型为:" << typeid(i).name() << endl;
}

Insert picture description here

Auto rules

  1. auto can be combined with pointers and references
int main()
{
	int i = 4;
	auto a1 = &i;
	auto *a2 = &i;
	auto& a3 = i;

	cout <<"a1的类型为:" << typeid(a1).name() << endl;
	cout << "a2的类型为:" << typeid(a2).name() << endl;
	cout << "a3的类型为:" << typeid(a3).name() << endl;
}

Insert picture description here
Because auto can recognize the pointer type, it can be added without *, but the reference must be added with &, because C ++ does not refer to this type, the reference is only a modified alias, so its essence is still int.

  1. Define multiple variables on the same line
int main()
{
	auto i = 1, j = 2; //正确,同一行都是相同类型
	auto x = 3, y = 4.8;//错误,同一行类型不同
}
  1. Auto cannot be used as a parameter of a function.
    Insert picture description here
    Auto cannot be used as a type of a formal parameter. The compiler cannot deduce the types of i and j.

  2. auto cannot be used directly to declare an array
    Insert picture description here

  3. auto generally ignores the top-level const

int main()
{
	const int i = 5;
	//i : const int 
	auto a1 = i;
	//忽略了顶层const ,al : int
	const auto a2 = i;
	//加上const, a2 : const int
}

Range for loop

For some collections with ranges, we may not know their length or accidentally cross the boundary when using loops. In order to solve this problem, c ++ 11 introduced a range for loop.

The loop is divided into two parts, the first part is the type of the variable, and the second part is the scope of the iteration, separated by: in between.

int main()
{
	vector<int> vec{ 1, 3, 5, 7, 9 };

	for (auto i : vec)
	{
		cout << i << ends;
	}

}

Insert picture description here
It should be noted that i is a temporary variable for copying the original data. If you want to modify the original data, you need to change it to & i (both references to the original data)


Published 60 original articles · praised 78 · views 6321

Guess you like

Origin blog.csdn.net/qq_35423154/article/details/105435404