C++primer function Advanced

Source: Internet
Author: User
Tags function definition function prototype square root

One, inline function

Inline functions are designed to improve efficiency, and the differences between them and ordinary functions do not appear in the form of writing, but in the way they are combined into the whole program. Each call of the function needs to open up the stack space, jump and so on a series of operations. For some function code less, and multiple use of functions, you can declare them as inline functions, the inline function in the program directly to the function calls to the actual code of the function, which will improve efficiency, but need to occupy more memory. In general, the inline function discards the declaration part and directly declares and defines the function in the part of the Declaration. When defining an inline function, simply precede the function return type with the keyword inline, but even if you declare this to be an inline function, the program does not necessarily actually follow the inline feature when combining this function, if the function has recursive invocation, Or the code is long, and even if you declare it as an inline function, he will not treat you as an inline function, only as a normal function.


For inline functions, the macro definitions in his and C languages are similar. But the difference between the two is mainly embodied in the transfer of function parameters.

inline functions, which are still strictly a function, pass function parameters according to the value passing rules of the function.

But this is not the case with macro definitions, when you define functions like functions with a macro definition, such as

#define Square (x) x * x

Using the macro definition to define a function to calculate the square root of a number, I have the following three ways to call

Square (1+5)

Square (c + +)

Both of these problems occur at the time of invocation, the first one will cause incorrect results due to improper operation order, and the second will cause the C variable to be 12 times the result of destroying the variable in a function call.

Why this happens, because the macro definition is implemented by text substitution and is not a function call in the real sense.

As a result, the first example should be 6, and the values of these constant expressions should be calculated at the compile stage of the program, and the corresponding positions replaced by the same constants. But the macro definition just makes a simple substitution. Overall, it's not smart enough. When defining a function of a class function, it cannot be implemented according to some rules of the function.


This is the best time for you to use an inline function, but the behavior is almost the same, but the inline function is a real function after all, and he will work out the value of the expression of the pass-through parameter and then pass it in accordance with the rules of the function passing parameters.

Therefore, it is better to use the inline function in the application of some function functions.


Second, reference variable

The reference variable is also a newly added compound type in the new C + + feature. It has an exact definition of the alias of the variable that is already defined. When binding a reference variable to a variable, the use of its own variables is the same as the use of reference variables.

So where is the greatest use of reference variables, which is the passing of function arguments.

From the simple discussion above you may know that the reference variable can use the actual variable that is bound to him, not copying a copy of a variable, but using the original data of the variable, which has a greater usefulness in passing some larger arrays and structures on the function parameters. Reference variables are relatively simple to use, at least a bit less prone to error than using pointers.

and can achieve the same effect as the pointer.


1, the definition of the reference

Give an example first

int A;

int &p = A;

P is a reference to this variable. The & operator Here is also a case of operator overloading when defining references here. It is no longer the address character, or bitwise AND operation, but a definition like char *, int & is a whole, indicating that p is a reference variable pointing to the int type data.

He is an alias of this variable, both pointing to the same piece of memory space.


There is a difference between a reference and a pointer to a variable. Like what

int *ptr = &a;

So ptr and &p are one thing, & here is the function of taking address

And when referring to definitions, one of the most important differences between pointers is that references must be initialized at the time of definition, but pointers are not used.

A reference is more like a const pointer, which must be initialized to a variable in the definition, so that the pointer or reference will always be bound to the variable at the time of initialization and cannot be re-directed to another variable.


The value of the reference changes, and can only be initialized at the time it is defined. If you try to make the reference variable change the previously bound variable through the assignment of a variable in a later program, the effect is only counterproductive. You will change the value of the variable initialized to the reference variable because of this behavior. In summary, a reference variable can only be initialized to specify the variable it is bound to, and cannot change its value after the assignment.

Once again, once the reference variable is initialized, it can no longer be changed.


2. Reference as function parameter

A very simple example is the function of exchanging two variables

int swap (int &a, int &b)

{

int t;

t = A;

A = b;

b = t;

}

As we all know, the inside of this function is no different from the swap function of passing a B to a value, but by value, the code in the function body cannot be converted. int swap (int a, int b); If this is the case, a B is a copy of the argument, that is, a copy of the argument, a B is two new variables and the arguments passed at the time of the call are not different. But the previous example initializes the variable to the reference variable, a b equals the alias of the argument, and the operation of AB is to manipulate the arguments passed by the caller, similar to pointers but not in the same way as pointers.



3, about the transfer of reference parameters and the creation of temporary variables

In the current standard, only the arguments of the called function are constant reference variables, the temporary variables are created during the function pass.

So when the reference parameter is const, what further conditions are needed to really determine the temporary variable to create, there are two cases:

(1) The type of the argument is correct, but is not an lvalue.

It is necessary to tell you that a concept is lvalue: Lvalue is a data object that can be referenced, such as variables, array elements, struct members, and so on, known as data Objects. Both regular and const variables can now be left values, but one is a modifiable lvalue, and the other is a non-modifiable lvalue. The left value is the data that can be accessed through the address

(2) The argument type is incorrect, such as a reference to be passed to a double, but the argument is a variable of type int.


There are two examples of the two cases described above

int temp (const int & t); A function prototype is like this.

Double X;

Temp (x);

Temp (2.5);

The first invocation is an incorrect argument type, at which point the compiler creates a temporary nameless variable, converts the x into an int variable, and then passes it to the reference parameter.

The second is that the argument is of the correct type, but is not an lvalue, which means that the argument passed is not a name. A temporary variable will also be created. Temporary variables exist only during function calls and can be deleted as soon as they are exhausted.

Why is it possible for a constant reference, but it is not feasible for other situations? First we want to make it clear that a constant reference, which binds a variable, but we cannot change the variable he binds to by this reference, if the reference is a regular reference, that is not the case.

Since he cannot use the reference to change the variable, it is actually the same as the value passing,

Long A = 5;

Long B = 3;

void swap (int &x, int &y);

Swap (A, B)

If it is done like this, then a B will create two temporary variables because the argument type is not correct, then bind the x y two reference parameter to two temporary variables, then the variable conversion, the conversion is a temporary variable, and the argument of a B is not any relationship. So when you want to modify an argument variable passed as a parameter, creating a temporary variable prevents it from happening. The only way to do this is to disallow the creation of temporary variables. The standard of C + + now stipulates that only a function parameter has a constant reference parameter to allow the creation of temporary variables, otherwise it will be an error or warning.


In summary, in a function referenced by a const parameter, if one of the two conditions mentioned above occurs, their behavior is similar to that of a value, because they do not change the original arguments because of the relationship of the temporary variables.


4. Use references for structure

Referring to a struct, one is passing a struct parameter to a reference parameter, and the other is the return value of the function.

There are three ways to pass a pointer, pass a value, and pass a reference while passing the structure parameter's procedure. Passing the value is not only inefficient and can not change the original argument, passing the pointer is more complex, passing the reference is a combination of the advantages of both.


The return value of the function, most of which is the same as the function passed by value, returns the value of the subsequent expression, then assigns the value to a temporary variable, after which the caller goes to use the value. However, passing a reference eliminates the need to pass the value to a temporary variable in the middle, and assigns it directly to the destination variable that accepts the return value of the function.

Also, when returning a reference, be careful not to return a reference to a local variable inside the function, because after the function is run, the corresponding stack space allocated to the function is recycled at once, and it is possible to return a reference to a variable that does not exist.

One way is to return a reference in the parameter, because the reference in the parameter is bound to the argument passed by the caller.


When the reference type of a function is a string object, the passed argument can be a string object, or a pointer to a char *, the literal of the string, the char array name ending with a null character.

On the one hand, the ability to convert C-style arrays to string is defined in string. On the other hand, if the reference parameter at this point is a const string, then he creates a temporary variable, puts the argument in, and binds a type to the correct reference.


5. Relation between inheritance and reference of class

Class, naturally there are base classes and derived classes. When defining a function of a base class, the object of the derived class can also invoke it. For reference, suppose that the parameter of a method of a base class is a reference variable of an object of a base class, but we can invoke this method when using a derived class object, and the passed argument is also an object of the derived class.



Third, default parameters

The definition of the default parameter is simple, which is a value that is automatically used when a function is called without passing the corresponding argument.

In the program we can set the value of the default function through the prototype of the function.

The only point when setting default parameters for a function is to note the order, which is the right-to-left order.

Also say, if you set a default parameter, then your right will be the default parameter, the left is the general parameters. This is because, in the process of calling a function to pass parameters, the arguments must be passed to the corresponding parameter in turn, and if your default parameter is in the middle, the program is not able to recognize your intentions, he will only pass the arguments to be passed to the next parameter in advance.

Defining default parameters must be defined in the prototype, and there is no difference between the definition of the function and the previous one.


Four, function overloading

The default function allows you to invoke the same function with different parameters, but the overloads of the function can call the same function with different parameters.

The key to function overloading is that the parameter list of the function becomes the special label of the function.

C + + allows you to define a function with the same name, but their argument list must be different, here the difference is the type, the order, not the name of the parameter.

As you can see, C + + relies on the function's signature to identify different functions.

When you overload a function to get a different version multiple times, the function that corresponds to its corresponding feature is automatically called during the call to the function.

But if this function is defined and several versions are overloaded, a call to a function is converted to a version of an existing function by using the coercion type conversion, which is called by a certain invocation of the functions that still cannot find the correct signature.

However, the problem also occurs during the coercion of type conversions.

For example, I define a function of int swap (int do) and overload him with int swap (char * p)

I use it when I call.

float x = 9.0

Swap (x)

Because the value of the passed X does not correspond to the type of the function's formal parameter, it is forced to cast because the double cannot be converted to a pointer, so it attempts to convert to int to continue the call.

But if you reload the function again, int swap (double dd);

There are two possible conversions at the same time, so the computer doesn't know what to do at this point.

It is also important to note that in function overloading, the compiler considers variables and their references to be the same feature label.

Other words

int swap (int yt)

int swap (int &yt)

int x = 9;

These two errors occur during the function overloading process. Swap (x) will match the above two versions, so the compiler does not know which function to invoke, which will result in an error.

And in the list of functions of the overloaded function, do not add no const as the determinant of the feature, the overloading of the function is not to distinguish between const and regular variables.

However, when passing parameters, it is important to note that the const parameter cannot be assigned to a non-const parameter, but the reverse is possible.


Overloading of functions, distinguishing between different versions is mainly dependent on the parameter list. There is nothing to do with the type of the function, the type of the function can be the same or different, but if your function name is the same and the signature is the same, then the compiler will determine that you have repeatedly defined two identical functions. Therefore, it is necessary to ensure that the feature is overloaded by the different features.


Five, function template

function templates, simply to define a common function. All of the data types in this function can be computed by passing the data type you want after the call, so it is convenient for those algorithms to be used for functions of different data types.

A template simply defines a function but does not create a function, but gives a whole framework that requires that we pass it to him with the appropriate type parameters to be able to actually use it.


How to define a function template:

Temlate <typename anytype>

void swap (Anytype &a, Anytype &b)

{

Anytype x;

x = A;

A = b;

b = x;

}

The code above defines a template for a function.

When you need to exchange data for two data types, the anytype becomes the corresponding data type, and the compiler creates the function based on the specified type according to the template. The early standard uses class instead of TypeName.


After defining the template for the function, we do not need to take care of the other things, or use these three steps to invoke the function according to the normal declaration definition. When you pass the data type explicitly, the compiler automatically generates a function for you to call for the version that corresponds to your data type. There are no templates present in the final executable program. As we can see, generating a deterministic function from a template is done in the compilation phase of the function. So the final result is the same as our hand-defined function, but the best advantage of applying a template is that the code is simple enough to reduce our error rate.


1. Heavy-duty Template

When you need to use the same algorithm for multiple different types, you can use function overloading or you can use a template. However, if different types require different algorithms. Then we need to reload the template. Overloaded templates and overloaded functions are really similar, and the important sign of overloading is that the feature labels are different. Of course temlate <typename anytype> should be the same, all the templates are used to start with this.


2. Limitations of templates

Because of the generic type of template functions, it is possible that a template cannot handle some types. For example, the function code is a = b * A. If it is an integer or a floating-point number then good, if the incoming AB is a pointer to two strings, this can not be processed.

A more straightforward approach is to specify a specific template for a particular type.


3. Display materialized

When using template code, if we need a different version of the code, but at the same time we can not change the template features, then we can not overload the template to achieve the purpose. So it is necessary to provide a definition of a specific function, which is called display materialization.

This includes the code that we need, and when the compiler finds a materialized definition that matches a function call, it no longer invokes the template and uses the materialization definition directly.


For a given function name, there can be regular functions, materialized functions, and template functions. If the above three functions exist at the same time, then in the choice of time, the priority is reduced in turn. That is, if you can find the corresponding regular function is not two, if the calling function found the corresponding data type of the function corresponding to the materialization function, then call this, preferably in the decision to invoke the template function.


The materialized function is defined as follows

template<> void Swap<job> (job&, job&) where <job> can be omitted, this materialized function is specifically prepared for the job data type, If the materialized function and the template function exist simultaneously, then the data of the job type will only invoke the materialized function.


4. Instantiation and Materialization

Instantiation:

A function template is not the definition of a function, but a schema that creates a function for the compiler. When we pass the function to the function data type in the usual way, we get the instantiated entity of a template, that is, a function of a certain type, the function is built by template. This instantiation is called an implicit instantiation.

So what is the display instantiation of the template void swap<int> (int&, int&)

Unlike display instantiation, Materialization uses such declarative methods

template<> void Swap<job> (job&, job&) where <job>

The main difference is that the declaration of materialization is not to use the template of a function to generate a function definition, but to generate a function for him separately. The display instantiation is a template that creates a specific type of function, and the <> behind it.


Another form of creating a display instantiation is to invoke the corresponding function directly in the program, so that the compiler will normally generate an instantiated function even if it is not in the same specification as the template and is not declared before. Like what

int x = 3;

Double y = 0.9

The swap template obviously does not correspond to a call such as swap (x, y). So using swap<double> (x, y) directly in the program, the compiler will force the generation of a double instantiation. And the type of the x parameter is converted to a double type, which matches the parameters easily.

It is no problem to pass only numbers here, if the parameters in the function template are references.

or the swap<double> (x, y) call. Although a double display instantiation swap<double> (double &a, double &b) is generated, the data of the integer type is not able to be bound to a reference of the double data type when the parameter is passed in later.


Display materialization, display instantiation, implicit instantiation are materialized. For implicit instantiation and display materialization, it is up to the appropriate invocation to decide which one to use, and the display materialization is defined manually before the program is run. However, the display instantiation is not, if the display is instantiated, only one declaration is required, then the template is used to define the corresponding version of the build. Implicit instantiation is a function that is generated by the compiler at the time of the function call, based on the data type of the passed parameter.


5, about Decltype

Decltype when declaring a template function, it can be helpful if you are unsure of what data type to use

For example, a two-number addition assigns a template function to a third variable, and three variables are a B C

c = A + b

Then the data type of C will be indeterminate, as there may be an elevation on the data type due to the different type of AB. So this time, using Decltype (a+b) c = A + B can solve the problem successfully. Changes c to the data type of the a+b result.


But what if you run into a template function like this?

? type? GT (t x2, t x1)

{

return x2 + x1;

}

If you want to use the type in Decltype, then it is wrong, because in the function return type, there is no definition of the X2 and X1 parameters, so it is not available.

In order to handle this situation, C + + uses a method called a back-return type.

Auto GT (t x2, T x1)->decltype (x+y)

In this case, the first with auto placeholder, and then with the following Decltype explicit type after the replacement of the previous auto.

This approach can also be used for function definitions

Auto Swap (t X, t y)->double

The return type of the function is finally double.

C++primer function Advanced

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.