Summary of functions in C++

  • 2020-04-02 02:13:19
  • OfStack

Function in C++ use, there are no more than two places, one is the definition of the function, one is the function call. The definition of a function is very simple and consists of three parts: the return type of the function, the function name, and the parameter list of the function. Of course, different function definitions can be slightly different here, such as class member functions, inline functions, and so on. Here we focus on some of the issues that need to be addressed when calling functions.

1. Parameter transfer

We call the arguments in the function definition or declaration formal arguments, and the arguments passed in when the function is called arguments. So depending on the parameter type, there are several forms of parameter passing.

1. Non-referential parameters

1) common built-in types

The parameter of ordinary non-reference type is initialized by copying the corresponding arguments. When initializing the parameter with a copy of the argument, the function does not access the argument itself passed by the call, so the function cannot change the value of the argument. For example, the following program exchanges two Numbers:


void swap(int v1, int v2)
{
    int temp = v1;
    v2 = v1;
    v1 = temp;
}
swap(a, b);//Call swap

In the above program, the arguments are a and b, but when called, v1 and v2 accept copies of a and b, so the values of a and b don't actually change.

2) pointer parameters

Function parameter can be a pointer, at this point will copy the argument pointer, in fact, this kind of similar to 1) principle, the function can not change the argument pointer value. Only the function can change the value of the argument pointer by the address to which it is copied.


void swap(int* v1, int* v2)
{
    int temp = *v2;
    *v2 = *v1;
    *v1 = temp;
}
int main()
{
    int a = 10,b = 20;
    int *p1 = &a,*p2 = &b;
    swap(p1,p2);
    return 0;
}

The formal parameter of swap defined in the above program is the pointer type, and swap is called in main. In fact, swap cannot change the values of p1 and p2, but only the values they point to.

3) const parameters

Const modification for normal non-reference types is actually meaningless because the function does not change the argument's value. Like the following definition, the compiler will actually ignore the const definition and treat it as an int.


void fcn(const int i);

2. Reference parameter

1) as we have seen in the above program, if you want to exchange the values of two variables, you cannot do so by calling ordinary functions of non-referential type parameters. We can use Pointers to them, and we can also use references.


void swap(int& v1, int& v2)
{
    int temp = v2;
    v2 = v1;
    v1 = temp;
}
int main()
{
    int a = 10,b = 20;
    swap(a,b);
    return 0;
}

When you actually call swap, v1 and v2 are actually equivalent to another name for a and b.

2) sometimes we need to pass a large object to a function, and we need to use a reference parameter. If we directly use the form of duplicate arguments, we can, but its efficiency is too low, and some objects cannot be copied. But when we use the reference parameter, we don't want the function to change the value of the argument passed in, so we can use const to qualify the parameter. The following program is used to determine which string is longer, obviously we don't want the function to change the content of the string, so we can use the const referential parameter.


bool isLonger(const string &s1, const string &s2)
{
    return s1.size() > s2.size();
}

So if the only purpose of using a reference parameter is to avoid duplicating arguments, you should define the parameter as a const reference.

3) there are two points worth noting when using the referential parameter function:

Do not call non-const reference parameter functions with const-qualified arguments or literals. Because in this case, you can change the value of the argument, which is illegal.

Non-const reference parameters can only be associated with non-const objects of exactly the same type.

4) pass a reference to a pointer

Here is the following procedure:


void swap(int* &v1, int* &v2)
{
    int* temp = v2;
    v2 = v1;
    v1 = temp;
}
int main()
{
    int a = 10,b = 20;
    int* p1 = &a, *p2 = &b;
    swap(p1,p2);
    return 0;
}

The program above still cannot change the values of a and b, but it has changed the values of p1 and p2, so that p1 now points to b and p2 to a.

3. Other types of formal parameters

1) vector and other types of parameters: generally, when this type is used as a parameter, the parameter should be declared as a reference type in order to avoid replication. C++ programmers tend to pass containers by iterators that pass the elements in the container that need to be processed.

2) array parameters: since the array cannot be copied, it is not possible to directly write the parameter function of array type, which is generally handled by passing Pointers to the elements of the array. It is important to note that when passing an array by reference, the type of the argument that the shape participates in when the function is called matches.


void printValues(int (&ar)[10]);
int main()
{
    int i = 0, j[2] = { 0, 1 };
    int k[10] = {0,1,2,3,4,5,6,7,8,9};
    printValues(i);  //Error int cannot initialize int(&)[10]
    printValues(j);  //Error int[2] cannot initialize int(&)[10]
    printValues(k);   // ok
    return 0;
}

The return value of the function

1) no return value

Many functions do not return a value, especially now that the C++ style is used to referring to the desired result as a parameter. This type of function usually does not have a return statement, and sometimes a return is used to break the execution of the function.

2) return non-reference types

In this case, at the function call, the program copies the return value of the function with a temporary variable.

3) return the reference

When a function returns a reference type, the return value is not copied. Instead, the object itself is returned.

In the case of a return reference, be careful not to return a reference to a local variable because the local variable is defined in the body of the function and is destroyed when the function is executed, so the reference is meaningless. Similarly, do not return a pointer to a local variable.

Overloaded functions

Two functions that appear in the same scope, if they have the same name but different parameters, are called overloaded functions.

1) pay attention to distinguish between function overload and repeated declaration

Some of the parameters that look different are essentially the same. The following code is full of examples of duplicate declarations


typedef double newDouble;
int func(double i);
int func(newDouble i);  //There is no new type
int func1(int, int = 1); //Just provide default parameters
int func1(int ,int);
int func2(int);
int func2(const int);  //It is meaningless to use cosnt for ordinary unreferenced parameters

2) overload and scope

Locally declared functions that mask all global functions of the same name. The following example shows that even though the global function better matches the argument type of the call, it still calls a local function.


void print(int);
int main()
{
    void print(double);
    print(42);
    return 0;
}

In the above program, the void print(double) function is called, although 42 is of type int.

3) reload the three steps identified

If many function overloads are defined, there is the question of which one the function call matches. We illustrate this with the following sample code:


void f();  // 1
void f(int);// 2
void f(double);// 3
void f(int, int);// 4
void f(double, double);// 5

Step 1: identify candidate functions

If we call f(4.2), we first find the function with the same name and we see it in scope. In the above example, all 5 functions satisfy.

Step 2: select the function that works

Two conditions must be satisfied: first, the number of arguments in the call is the same; Second, the type of each argument must match the corresponding type, or it can be implicitly converted to the corresponding parameter type. When we call f(4.2) again, we exclude functions 1, 4, and 5, leaving only 2 and 3. The number 2 function can be satisfied by type conversion.

Step 3: find the best match

After the second step, we are left with 2 and 3 functions, so 2 needs to be cast, and obviously 3 is the best match.

But if I call f(42,4.2) this way. At this point ambiguity will appear and the compiler will prompt.

Another thing to note is that functions with default arguments, for example, we define the function 6 as void f(double,int =1); Then there is ambiguity when f(4.2) is called.

Function overloading can be implemented based on whether a function reference parameter points to a const object or to a non-const object.


Related articles: