Summary

Section 6.1 Introduction

  • Experience has shown that the best way to develop and maintain a large program is to construct it from small, simple pieces, or components. This technique is called divide and conquer (p. 212).

Section 6.2 Program Components in C++

  • C++ programs are typically written by combining new functions and classes you write with “prepackaged” functions and classes available in the C++ Standard Library.

  • Functions allow you to modularize a program by separating its tasks into self-contained units.

  • The statements in the function bodies are written only once, are reused from perhaps several locations in a program and are hidden from other functions.

Section 6.3 Math Library Functions

  • Sometimes functions are not members of a class. These are called global functions (p. 214).

  • The prototypes for global functions are often placed in headers, so that they can be reused in any program that includes the header and that can link to the function’s object code.

Section 6.4 Function Prototypes

  • For a function that’s not defined in a class, you must either define the function before using it or you must declare that the function exists by using a function prototype.

  • A function prototype (p. 217) is a declaration of a function that tells the compiler the function’s name, its return type and the types of its parameters

  • A function prototype ends with a required semicolon.

  • Parameter names in function prototypes are optional (they’re ignored by the compiler), but many programmers use these names for documentation purposes.

  • The compiler uses the prototype to ensure that the function header matches the function prototype; to check that each function call contains the correct number and types of arguments and that the types of the arguments are in the correct order; to ensure that the value returned by the function can be used correctly in the calling expression; and to ensure that each argument is consistent with the type of the corresponding parameter.

  • In a function with a void return type, control returns to the caller when the program reaches the function-ending right brace or by executing the statement

    
    return;
    

Section 6.5 Function-Prototype and Argument-Coercion Notes

  • The portion of a function prototype that includes the name of the function and the types of its arguments is called the function signature (p. 219) or simply the signature.

  • An important feature of function prototypes is argument coercion (p. 219)—i.e., forcing arguments to the appropriate types specified by the parameter declarations.

  • Arguments can be converted by the compiler to the parameter types as specified by C++’s promotion rules (p. 219). The promotion rules indicate the implicit conversions that the compiler can perform between fundamental types.

Section 6.6 C++ Standard Library Headers

  • The C++ Standard Library is divided into many portions, each with its own header. The headers also contain definitions of various class types, functions and constants.

  • A header “instructs” the compiler on how to interface with library components.

Section 6.7 Case Study: Random-Number Generation

  • Calling rand (p. 222) repeatedly produces a sequence of pseudorandom numbers (p. 226). The sequence repeats itself each time the program executes.

  • To make numeric literals more readable, C++14 allows you to insert between groups of digits in numeric literals the digit separator ' (p. 225; a single-quote character).

  • To randomize the numbers produced by rand, pass an unsigned integer argument (typically from function time; p. 227) to function srand (p. 226), which seeds the rand function.

  • Random numbers in a range can be generated with

    
    type variableName{shiftingValue + rand() % scalingFactor};
    

    where shiftingValue (p. 227) is equal to the first number in the desired range of consecutive integers and scalingFactor (p. 227) is equal to the width of the desired range of consecutive integers.

Section 6.8 Case Study: Game of Chance; Introducing Scoperd enums

  • A scoped enumeration (p. 230)—introduced by the keywords enum class followed by a type name—is a set of named integer constants that start at 0, unless specified otherwise, and increment by 1.

  • To reference a scoped enum constant, you must qualify the constant with the scoped enum’s type name and the scope resolution operator (::). If another scoped enum contains the same identifier for one of its constants, it’s always clear which version of the constant is being used.

  • A scoped enum’s underlying integral type is int by default.

  • C++11 allows you to specify an enum’s underlying integral type by following the enum’s type name with a colon (:) and the integral type.

  • A compilation error occurs if an enum constant’s value is outside the range that can be represented by the enum’s underlying type.

  • Unscoped enums can lead to naming collisions and logic errors.

  • An unscoped enum’s underlying integral type depends on its constants’ values—the type is guaranteed to be large enough to store the constant values specified.

Section 6.9 C++11 Random Numbers

  • According to CERT, function rand does not have “good statistical properties” and can be predictable, which makes programs that use rand less secure.

  • C++11 provides a new, more secure library of random-number capabilities that can produce nondeterministic random numbers for simulations and security scenarios where predictability is undesirable. These new capabilities are located in the C++ Standard Library’s <random> header.

  • For flexibility based on how random numbers are used in programs, C++11 provides many classes that represent various random-number generation engines and distributions. An engine implements a random-number generation algorithm that produces pseudorandom numbers. A distribution controls the range of values produced by an engine, the types of those values and the statistical properties of the values.

  • A default_random_engine (p. 232) represents the default random-number generation engine.

  • The uniform_int_distribution (p. 232) evenly distributes pseudorandom integers over a specified range of values. The default range is from 0 to the maximum value of an int on your platform.

Section 6.10 Scope Rules

  • An identifier declared outside any function or class has global namespace scope (p. 233).

  • Global variable (p. 234) declarations are placed outside any class or function definition. Global variables retain their values throughout the program’s execution. Global variables and functions can be referenced by any function that follows their declarations or definitions.

  • Identifiers declared inside a block have block scope (p. 233), which begins at the identifier’s declaration and ends at the terminating right brace (}) of the block in which the identifier is declared.

  • static (p. 234) local variables also have block scope, but retain their values when the function in which they’re declared returns to its caller.

  • An identifier declared outside any function or class has global namespace scope. Such an identifier is “known” in all functions from the point at which it’s declared until the end of the file.

Section 6.11 Function-Call Stack and Activation Records

  • Stacks (p. 237) are known as last-in, first-out (LIFO) data structures—the last item pushed (inserted; p. 237) on the stack is the first item popped (removed; p. 237) from the stack.

  • The function-call stack (p. 237) supports the function call/return mechanism and the creation, maintenance and destruction of each called function’s non-static local variables.

  • Each time a function calls another function, a stack frame or an activation record (p. 237) is pushed onto the stack containing the return address that the called function needs to return to the calling function, and the function call’s non-static local variables and parameters.

  • The stack frame exists as long as the called function is active. When the called function returns, its stack frame is popped from the stack, and its non-static local variables no longer exist.

Section 6.12 Inline Functions

  • C++ provides inline functions (p. 241) to help reduce function-call overhead—especially for small functions. Placing the qualifier inline (p. 241) before a function’s return type in the function definition advises the compiler to generate a copy of the function’s code in every place that the function is called to avoid a function call.

  • Compilers can inline code for which you have not explicitly used the inline keyword. Today’s optimizing compilers are so sophisticated that it’s best to leave inlining decisions to the compiler.

Section 6.13 References and Reference Parameters

  • With pass-by-value (p. 242), a copy of the argument’s value is made and passed to the called function. Changes to the copy do not affect the original variable’s value in the caller.

  • With pass-by-reference (p. 242), the caller gives the called function the ability to access the caller’s data directly and to modify it if the called function chooses to do so.

  • A reference parameter (p. 243) is an alias for its corresponding argument in a function call.

  • To indicate that a function parameter is passed by reference, follow the parameter’s type in the function prototype and header by an ampersand (&).

  • All operations performed on a reference are actually performed on the original variable.

Section 6.14 Default Arguments

  • When a function is called repeatedly with the same argument for a particular parameter, you can specify that such a parameter has a default argument (p. 245).

  • When a program omits an argument for a parameter with a default argument, the compiler inserts the default value of that argument to be passed to the function call.

  • Default arguments must be the rightmost (trailing) arguments in a function’s parameter list.

  • Default arguments are specified in the function prototype.

Section 6.15 Unary Scope Resolution Operator

  • C++ provides the unary scope resolution operator (p. 247; ::) to access a global variable when a local variable of the same name is in scope.

Section 6.16 Function Overloading

  • C++ enables several functions of the same name to be defined, as long as these functions have different sets of parameters. This capability is called function overloading (p. 248).

  • When an overloaded function is called, the C++ compiler selects the proper function by examining the number, types and order of the arguments in the call.

  • Overloaded functions are distinguished by their signatures.

  • The compiler encodes each function identifier with the types of its parameters to enable type-safe linkage (p. 249). Type-safe linkage ensures that the proper overloaded function is called and that the types of the arguments conform to the types of the parameters.

Section 6.17 Function Templates

  • Overloaded functions typically perform similar operations that involve different program logic on different data types. If the program logic and operations are identical for each data type, overloading may be performed more compactly and conveniently using function templates (p. 251).

  • Given the argument types provided in calls to a function template, C++ automatically generates separate function template specializations (p. 251) to handle each type of call appropriately.

  • All function template definitions begin with the template keyword (p. 251) followed by a template parameter list (p. 251) enclosed in angle brackets (< and >).

  • The type parameters (p. 252) are preceded by keyword typename (or class) and are placeholders for fundamental types or user-defined types. These placeholders are used to specify the types of the function’s parameters, to specify the function’s return type and to declare variables within the body of the function definition.

Section 6.18 Recursion

  • A recursive function (p. 254) calls itself, either directly or indirectly.

  • A recursive function knows how to solve only the simplest case(s), or so-called base case(s). If the function is called with a base case (p. 254), the function simply returns a result.

  • If the function is called with a more complex problem, the function typically divides the problem into two conceptual pieces—a piece that the function knows how to do and a piece that it does not know how to do. To make recursion feasible, the latter piece must resemble the original problem, but be a slightly simpler or slightly smaller version of it.

  • For recursion to terminate, the sequence of recursive calls (p. 254) must converge on the base case.

  • C++11’s unsigned long long int type (which can be abbreviated as unsigned long long) on some systems enables you to store values in at least 8 bytes (64 bits) which can hold numbers as large as 18,446,744,073,709,551,615.

Section 6.19 Example Using Recursion: Fibonacci Series

  • The ratio of successive Fibonacci numbers converges on a constant value of 1.618…. This number frequently occurs in nature and has been called the golden ratio or the golden mean (p. 257).

Section 6.20 Recursion vs. Iteration

  • Iteration and recursion are similar: both are based on a control statement, involve iteration, involve a termination test, gradually approach termination and can occur infinitely.

  • Recursion repeatedly invokes the mechanism, and overhead, of function calls. This can be expensive in both processor time and memory space. Each recursive call (p. 254) causes another copy of the function’s variables to be created; this can consume considerable memory.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset