官术网_书友最值得收藏!

  • C++ Fundamentals
  • Antonio Mallia Francesco Zoffoli
  • 866字
  • 2021-06-11 13:35:59

Passing Arguments and Returning Values

In the Introduction section, we mentioned that the caller can provide some data to the function. This is done by passing arguments to the parameters of the function.

The parameters that a function accept are part of its signature, so we need to specify them in every declaration.

The list of parameters a function can accept is contained in the parentheses after the function name. The parameters in the function parentheses are comma-separated, composed by a type, and optionally an identifier.

For example, a function taking two integer numbers would be declared as follows:

void two_ints(int, int);

If we wanted to give a name to these parameters, a and b respectively, we would write the following:

void two_ints(int a, int b);

Inside its body, the function can access the identifiers defined in the function signature as if they were declared variables. The values of the function parameters are decided when the function is called.

To call a function that takes a parameter, you need to write the name of the function, followed by a list of expressions inside a pair of parentheses:

two_ints(1,2);

Here, we called the two_ints function with two arguments: 1 and 2.

The arguments used to call the function initialize the parameters that the function is expecting. Inside the two_ints function, variable a will be equal to 1, and b will be equal to 2.

Each time the function is called, a new set of parameters is initialized from the arguments that were used to call the function.

Note

Parameter: This is a variable that was defined by a function, and can be used to provide data as per the code.

Argument: The value the caller wants to bind to the parameters of the function.

In the following example, we used two values, but we can also use arbitrary expressions as arguments:

two_ints(1+2, 2+3);

Note

The order in which the expression is evaluated is not specified!

This means that when calling two_ints(1+2, 2+3);, the compiler might first execute 1+2 and then 2+3, or 2+3 and then 1+2. This is usually not a problem if the expression does not change any state in the program, but it can create bugs that are hard to detect when it does. For example, given int i = 0;, if we call two_ints(i++, i++), we don't know whether the function is going to be called with two_ints(0, 1) or two_ints(1, 0).

In general, it's better to declare expressions that change the state of the program in their own statements, and call functions with expressions that do not modify the program's state.

The function parameters can be of any type. As we already saw, a type in C++ could be a value, a reference, or a pointer. This gives the programmer a few options on how to accept parameters from the callers, based on the behavior it wants.

In the following subsections, we will explore the working mechanism of Pass by value and Pass by reference in more detail.

Pass by Value

When the parameter type of a function is a value type, we say that the function is taking an argument by value or the argument is passed by value.

When a parameter is a value type, a new local object is created each time the function is called.

As we saw with automatic variables, the lifetime of the object lasts until the execution does not reach the end of the function's scope.

When the parameter is initialized, a new copy is made from the argument provided when invoking the function.

Note

If you want to modify a parameter but do not want or do not care about the calling code seeing the modification, use pass by value.

Exercise 5: Calculating Age using Pass by Value Arguments

James wants to write a C++ program to calculate what the age of a person will be after five years by providing their current age as an input.

To implement such a program, he is going to write a function that takes a person's age by value and computes how old they will be in 5 years, and then prints it on the screen:

  1. Create a function named byvalue_age_in_5_years, as illustrated here. Make sure that the value in the calling code does not change:

    void byvalue_age_in_5_years(int age) {

    age += 5;

    std::cout << "Age in 5 years: " << age << std::endl;

    // Prints 100

    }

  2. Now, in main(), call the function we created in the previous step by passing the variable age as a value:

    int main() {

    int age = 95;

    byvalue_age_in_5_years(age);

    std::cout << "Current age: " << age;

    // Prints 95

    }

    Note

    Pass by value should be the default way of accepting arguments: always use it unless you have a specific reason not to.

    The reason for this is that it makes the separation between the calling code and the called function stricter: the calling code cannot see the changes that the called function makes on the parameters.

Passing parameters by value creates a clear boundary between the calling function and the called function, because the parameters are copied:

  1. As the calling function, we know that the variables we passed to the functions will not be modified by it.
  2. As the called function, we know that even if we modify the provided parameters, there will be no impact on the called function.

This makes it easy to understand the code, because the changes we make to the parameters have no impact outside of the function.

Pass by value can be the faster option when taking an argument, especially if the memory size of the argument is small (for example, integers, characters, float, or small structures).

We need to remember though that passing by value performs a copy of the argument. Sometimes, this can be an expensive operation both in terms of memory and processing time, like when copying a container with many elements.

There are some cases where this limitation can be overcome with the move semantic that was added in C++11. We will see more of it in Lesson 3, Classes.

Let's look at an alternative to pass by value that has a different set of properties.

Pass by Reference

When the parameter type of the function is a reference type, we say that the function is taking an argument by reference or the argument is passed by reference.

We saw earlier that a reference type does not create a new object – it is simply a new variable, or name that refers to an object that already exists.

When the function that accepts the argument by reference is called, the reference is bound to the object used in the argument: the parameter will refer to the given object. This means that the function has access to the object the calling code provided and can modify it.

This is convenient if the goal of the function is to modify an object, but it can be more difficult to understand the interaction between the caller and the called function in such situations.

Note

Unless the function must modify the variable, always use const references, as we will see later.

Exercise 6: Calculating Incrementation of Age using Pass by Reference

James would like to write a C++ program which, given anyone's age as input, prints Congratulations! if their age will be 18 or older in the next 5 years.

Let's write a function that accepts its parameters by reference:

  1. Create a function named byreference_age_in_5_years() of type void, as illustrated here:

    void byreference_age_in_5_years(int& age) {

    age += 5;

    }

  2. Now, in main(), call the function we created in the previous step by passing the variable age as a reference:

    int main() {

    int age = 13;

    byreference_age_in_5_years(age);

    if (age >= 18) {

    std::cout << "Congratulations! " << std::endl;

    }

    }

Contrary to passing by value the speed when passing by reference does not change when the memory size of the object passed.

This makes pass by reference the preferred method when copying an object, since providing pass by value to the function is expensive, especially if we cannot use the move semantic that was added in C++11.

Note

If you want to use pass by reference, but you are not modifying the provided object, make sure to use const.

With C++, we can use std::cin to read input from the console executing the program.

When writing std::cin >> variable;, the program will block waiting for some user input, and then it will populate variable with the value read from the input as long as it is a valid value and the program knows how to read it. By default, we can assign all the built-in data types and some types defined in the standard library, such as string.

Activity 3: Checking Voting Eligibility

James is creating a program to print a message on the console screen: "Congratulations! You are eligible to vote in your country" or "No worries, just <value> more years to go." after the user provides their current age as input.

  1. Create a function named byreference_age_in_5_years(int& age) and add the following code:

    #include <iostream>

    void byreference_age_in_5_years(int& age) {

    if (age >= 18) {

    std::cout << "Congratulations! You are eligible to vote for your nation." << std::endl;

    return;

  2. In the else block, add the code to calculate the years remaining until they can vote:

    } else{

    int reqAge = 18;

    }

    }

  3. In main(), add the input stream, as illustrated, to accept the input from the user. Pass the value as a reference in the previous function:

    int main() {

    int age;

    std::cout << "Please enter your age:";

    std::cin >> age;

    The solution for this activity can be found on page 284.

主站蜘蛛池模板: 潍坊市| 如东县| 杭锦后旗| 安乡县| 临湘市| 永嘉县| 崇信县| 保康县| 吐鲁番市| 措勤县| 桦南县| 漯河市| 哈尔滨市| 孙吴县| 大足县| 鄯善县| 营山县| 高雄县| 鄂伦春自治旗| 平山县| 敦化市| 泸水县| 太白县| 盐亭县| 仁布县| 泸定县| 上蔡县| 顺昌县| 台江县| 修武县| 阳朔县| 三门峡市| 瑞昌市| 安多县| 荥阳市| 乐东| 怀化市| 六安市| 平潭县| 赞皇县| 名山县|