5.x — Chapter 5 summary and quiz

Chapter Review

A constant is a value that may not be changed during the program’s execution. C++ supports two types of constants: named constants, and literals.

A named constant is a constant value that is associated with an identifier. Constant variables are one type of named constant, as are object-like macros with substitution text.

Literal constants are constant values not associated with an identifier.

A variable whose value can not be changed is called a constant variable. The const keyword can be used to make a variable constant. Constant variables must be initialized. Avoid using const when passing by value or returning by value.

A type qualifier is a keyword that is applied to a type that modifies how that type behaves. As of C++23, C++ only supports const and volatile as type qualifiers.

A constant expression is an expression that can be evaluated at compile-time. An expression that must be evaluated at runtime is sometimes called a runtime expression.

A compile-time constant is a constant whose value is known at compile-time. A runtime constant is a constant whose initialization value isn’t known until runtime.

A constexpr variable must be a compile-time constant, and initialized with a constant expression. Function parameters may not be constexpr.

Literals are values inserted directly into the code. Literals have types, and literal suffixes can be used to change the type of a literal from the default type.

A magic number is a literal (usually a number) that either has an unclear meaning or may need to be changed later. Don’t use magic numbers in your code. Instead, use symbolic constants.

In everyday life, we count using decimal numbers, which have 10 digits. Computers use binary, which only has 2 digits. C++ also supports octal (base 8) and hexadecimal (base 16). These are all examples of numeral systems, which are collections of symbols (digits) used to represent numbers.

The conditional operator (?:) (also sometimes called the arithmetic if operator) is a ternary operator (an operator that takes 3 operands). Given a conditional operation of the form c ? x : y, if conditional c evaluates to true then x will be evaluated, otherwise y will be evaluated. The conditional operator typically needs to be parenthesized as follows:

  • Parenthesize the entire conditional operator when used in a compound expression (an expression with other operators).
  • For readability, parenthesize the condition if it contains any operators (other than the function call operator).

Inline expansion is a process where a function call is replaced by the code from the called function’s definition. A function that is declared using the inline keyword is called an inline function.

Inline functions and variables have two primary requirements:

  • The compiler needs to be able to see the full definition of an inline function or variable in each translation unit where the function is used (a forward declaration will not suffice on its own). The definition can occur after the point of use if a forward declaration is also provided.
  • Every definition for an inline function or variable must be identical, otherwise undefined behavior will result.

In modern C++, the term inline has evolved to mean “multiple definitions are allowed”. Thus, an inline function is one that is allowed to be defined in multiple files. C++17 introduced inline variables, which are variables that are allowed to be defined in multiple files.

Inline functions and variables are particularly useful for header-only libraries, which are one or more header files that implement some capability (no .cpp files are included).

A constexpr function is a function whose return value may be computed at compile-time. To make a function a constexpr function, we simply use the constexpr keyword in front of the return type. Constexpr functions are only guaranteed to be evaluated at compile-time when used in a context that requires a constant expression. Otherwise they may be evaluated at compile-time (if eligible) or runtime.

A consteval function is a function that must evaluate at compile-time.

Constexpr functions and consteval functions are implicitly inline.

A string is a collection of sequential characters that is used to represent text (such as names, words, and sentences). String literals are always placed between double quotes. String literals in C++ are C-style strings, which have a strange type that is hard to work with.

std::string offers an easy and safe way to deal with text strings. std::string lives in the <string> header. std::string is expensive to initialize and copy.

std::string_view provides read-only access to an existing string (a C-style string literal, a std::string, or a char array) without making a copy. A std::string_view that is viewing a string that has been destroyed is sometimes called a dangling view. When a std::string is modified, all views into that std::string are invalidated, meaning those views are now invalid. Using an invalidated view (other than to revalidate it) will produce undefined behavior.

Because C-style string literals exist for the entire program, it is okay to set a std::string_view to a C-style string literal, and even return such a std::string_view from a function.

A substring is a contiguous sequence of characters within an existing string.

Quiz time

Question #1

Why are named constants often a better choice than literal constants?

Why are const/constexpr variables usually a better choice than #defined symbolic constants?

Show Solution

Question #2

Find 3 issues (affecting 4 lines) in the following code.

#include <cstdint> // for std::uint8_t
#include <iostream>

int main()
{
  std::cout << "How old are you?\n";

  std::uint8_t age{};
  std::cin >> age;

  std::cout << "Allowed to drive a car in Texas [";

  if (age >= 16)
    std::cout << "x";
  else
    std::cout << " ";

  std::cout << "]\n";

  return 0;
}

Sample output

How old are you?
6
Allowed to drive a car in Texas [ ]
How old are you?
19
Allowed to drive a car in Texas [x]

Show Solution

Question #3

Add const and/or constexpr to the following program:

#include <iostream>

// gets height from user and returns it
double getTowerHeight()
{
	std::cout << "Enter the height of the tower in meters: ";
	double towerHeight{};
	std::cin >> towerHeight;
	return towerHeight;
}

// Returns height from ground after "seconds" seconds
double calculateHeight(double towerHeight, int seconds)
{
	double gravity{ 9.8 };

	// Using formula: [ s = u * t + (a * t^2) / 2 ], here u(initial velocity) = 0
	double distanceFallen{ (gravity * (seconds * seconds)) / 2.0 };
	double currentHeight{ towerHeight - distanceFallen };

	return currentHeight;
}

// Prints height every second till ball has reached the ground
void printHeight(double height, int seconds)
{
	if (height > 0.0)
		std::cout << "At " << seconds << " seconds, the ball is at height: " << height << " meters\n";
	else
		std::cout << "At " << seconds << " seconds, the ball is on the ground.\n";
}

void calculateAndPrintHeight(double towerHeight, int seconds)
{
	double height{ calculateHeight(towerHeight, seconds) };
	printHeight(height, seconds);
}

int main()
{
	double towerHeight{ getTowerHeight() };

	calculateAndPrintHeight(towerHeight, 0);
	calculateAndPrintHeight(towerHeight, 1);
	calculateAndPrintHeight(towerHeight, 2);
	calculateAndPrintHeight(towerHeight, 3);
	calculateAndPrintHeight(towerHeight, 4);
	calculateAndPrintHeight(towerHeight, 5);

	return 0;
}

Show Solution

Question #4

What are the primary differences between std::string and std::string_view?

What can go wrong when using a std::string_view?

Show Solution

Question #5

Write a program that asks for the name and age of two people, then prints which person is older.

Here is the sample output from one run of the program:

Enter the name of person #1: John Bacon
Enter the age of John Bacon: 37
Enter the name of person #2: David Jenkins
Enter the age of David Jenkins: 44
David Jenkins (age 44) is older than John Bacon (age 37).

Show Hint

Show Solution

Question #6

Complete the following program:

#include <iostream>

// Write the function getQuantityPhrase() here

// Write the function getApplesPluralized() here

int main()
{
    std::cout << "Mary has " << getQuantityPhrase(3) << " " << getApplesPluralized(3) << ".\n";

    std::cout << "How many apples do you have? ";
    int numApples{};
    std::cin >> numApples;

    std::cout << "You have " << getQuantityPhrase(numApples) << " " << getApplesPluralized(numApples) << ".\n";
 
    return 0;
}

Sample output:

Mary has a few apples.
How many apples do you have? 1
You have a single apple.

getQuantityPhrase() should take a single int parameter representing the quantity of something and return the following descriptor:

  • 0 = “no”
  • 1 = “a single”
  • 2 = “a couple of”
  • 3 = “a few”
  • >3 = “many”

getApplesPlural() should take a single int parameter parameter representing the quantity of apples and return the following:

  • 1 = “apple”
  • otherwise = “apples”

This function should use the conditional operator.

Both functions should make proper use of constexpr.

Show Hint

Show Solution

guest
Your email address will not be displayed
Find a mistake? Leave a comment above!
Correction-related comments will be deleted after processing to help reduce clutter. Thanks for helping to make the site better for everyone!
Avatars from https://gravatar.com/ are connected to your provided email address.
Notify me about replies:  
9 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments