LearnC++___CH4

4.1 — Introduction to fundamental data types

Data types

All you need to do is pick a data type for your object that best matches your desired use.


Fundamental data types

C++ comes with built-in support for many different data types. These are called fundamental data types, but are often informally called basic types, primitive types, or built-in types.


As an aside…

Most modern programming languages include a fundamental string type (strings are a data type that lets us hold a sequence of characters, typically used to represent text). In C++, strings aren’t a fundamental type (they’re a compound type). But because basic string usage is straightforward and useful, we’ll introduce strings in this chapter as well (in lesson 4.17 – Introduction to std::string).


The _t suffix

Many of the types defined in newer versions of C++ (e.g. std::nullptr_t) use a _t suffix. This suffix means “type”, and it’s a common nomenclature applied to modern types.

If you see something with a _t suffix, it’s probably a type. But many types don’t have a _t suffix, so this isn’t consistently applied.

4.2 — Void

Functions that do not return a value


Deprecated: Functions that do not take parameters

4.3 — Object sizes and the sizeof operator

4.4 — Signed integers

Defining signed integers

Here is the preferred way to define the four types of signed integers:

short s;      // prefer "short" instead of "short int"
int i;
long l;       // prefer "long" instead of "long int"
long long ll; // prefer "long long" instead of "long long int"

4.5 — Unsigned integers, and why to avoid them

The controversy over unsigned numbers

Best practice

Favor signed numbers over unsigned numbers for holding quantities (even quantities that should be non-negative) and mathematical operations. Avoid mixing signed and unsigned numbers.


So when should you use unsigned numbers?

There are still a few cases in C++ where it’s okay / necessary to use unsigned numbers.

First, unsigned numbers are preferred when dealing with bit manipulation (covered in chapter O – that’s a capital ‘o’, not a ‘0’). They are also useful when well-defined wrap-around behavior is required (useful in some algorithms like encryption and random number generation).

Second, use of unsigned numbers is still unavoidable in some cases, mainly those having to do with array indexing. We’ll talk more about this in the lessons on arrays and array indexing. In these cases, the unsigned value can be converted to a signed value.

4.6 — Fixed-width integers and size_t

Why isn’t the size of the integer variables fixed?


Doesn’t this suck?


std::int8_t and std::uint8_t likely behave like chars instead of integers

For consistency, it’s best to avoid std::int8_t and std::uint8_t (and the related fast and least types) altogether (use std::int16_t or std::uint16_t instead).


Integral best practices

Given the various pros and cons of the fundamental integral types, the fixed-width integral types, the fast/least integral types, and signed/unsigned challenges, there is little consensus on integral best practices.

Our stance is that it’s better to be correct than fast, better to fail at compile time than runtime – therefore, we recommend avoiding the fast/least types in favor of the fixed-width types. If you later discover the need to support a platform for which the fixed-width types won’t compile, then you can decide how to migrate your program (and thoroughly test) at that point.

4.7 — Introduction to scientific notation

4.8 — Floating point numbers

4.9 — Boolean values

Boolean variables


Printing Boolean values

4.10 — Introduction to if statements

Question #2

How can the length of the following code be reduced (without changing the formatting)?
#include

bool isAllowedToTakeFunRide()
{
  std::cout << "How tall are you? (cm)\n";

  double height{};
  std::cin >> height;

  if (height > 140.0)
    return true;
  else
    return false;
}

int main()
{
  if (isAllowedToTakeFunRide())
    std::cout << "Have fun!\n";
  else
    std::cout << "Sorry, you're too short.\n";

  return 0;
}

We don’t need the if-statement in isAllowedToTakeFunRide(). The expression height > 140.0 evaluates to a bool, which can be directly returned.

bool isAllowedToTakeFunRide()
{
  std::cout << "How tall are you? (cm)\n";

  double height{};
  std::cin >> height;

  return (height > 140.0);
}

You never need an if-statement of the form:

if (condition)
  return true;
else
  return false;

This can be replaced by the single statement return condition.

4.11 — Chars

Initializing chars

Warning

Be careful not to mix up character numbers with integer numbers. The following two initializations are not the same:

char ch{5}; // initialize with integer 5 (stored as integer 5)
char ch{'5'}; // initialize with code point for '5' (stored as integer 53)

Character numbers are intended to be used when we want to represent numbers as text, rather than as numbers to apply mathematical operations to.

Escape sequences

Warning

Escape sequences start with a backslash (), not a forward slash (/). If you use a forward slash by accident, it may still compile, but will not yield the desired result.


What’s the difference between putting symbols in single and double quotes?

Best practice

Put stand-alone chars in single quotes (e.g. ‘t’ or ‘\n’, not “t” or “\n”). This helps the compiler optimize more effectively.

Avoid multicharacter literals

Warning

Make sure that your newlines are using escape sequence ‘\n’ , not multicharacter literal ‘/n’.

What about the other char types, wchar_t, char16_t, and char32_t?

As an aside…

The term “deprecated” means “still supported, but no longer recommended for use, because it has been replaced by something better or is no longer considered safe”.

4.12 — Introduction to type conversion and static_cast

Implicit type conversion

When the compiler does type conversion on our behalf without us explicitly asking, we call this implicit type conversion.

Type conversion produces a new value

Key insight

Type conversion produces a new value of the target type from a value of a different type.

An introduction to explicit type conversion via the static_cast operator

Using static_cast to convert char to int

It’s worth noting that the argument to static_cast evaluates as an expression. When we pass in a variable, that variable is evaluated to produce its value, and that value is then converted to the new type. The variable itself is not affected by casting its value to a new type. In the above case, variable ch is still a char, and still holds the same value even after we’ve cast its value to an int.


std::int8_t and std::uint8_t likely behave like chars instead of integers

In cases where std::int8_t is treated as a char, input from the console can also cause problems:

#include <cstdint>
#include <iostream>

int main()
{
    std::cout << "Enter a number between 0 and 255: ";
    std::int8_t myint{};
    std::cin >> myint;

    std::cout << "You entered: " << static_cast<int>(myint);

    return 0;
}

A sample run of this program:

Enter a number between 0 and 255: 35
You entered: 51

Here’s what’s happening. When std::int8_t is treated as a char, the input routines interpret our input as a sequence of characters, not as an integer. So when we enter 35, we’re actually entering two chars, ‘3’ and ‘5’. Because a char object can only hold one character, the ‘3’ is extracted (the ‘5’ is left in the input stream for possible extraction later). Because the char ‘3’ has ASCII code point 51, the value 51 is stored in myint, which we then print later as an int.

In contrast, the other fixed-width types will always print and input as integral values.

4.13 — Const variables and symbolic constants

Naming your const variables

However, because const variables act like normal variables (except they can not be assigned to), there is no reason that they need a special naming convention. For this reason, we prefer using the same naming convention that we use for non-const variables (e.g. earthGravity).

Const function parameters

Best practice

Don’t use const when passing by value.

Const return values

Best practice

Don’t use const when returning by value.


What is a symbolic constant?


For symbolic constants, prefer constant variables to object-like macros

So why not use #define to make symbolic constants? There are (at least) three major problems.

4.14 — Compile-time constants, constant expressions, and constexpr

Constant expressions

A constant expression is an expression that can be evaluated by the compiler at compile-time.

#include <iostream>

int main()
{
	int x { 7 };
	std::cout << x << '\n';

	return 0;
}

This program produces the same output (7), but the resulting executable no longer needs to spend CPU cycles calculating 3 + 4 at runtime!

Note that the expression std::cout << x is not a constant expression, because our program can’t output values to the console at compile-time. So this expression will always evaluate at runtime.

The constexpr keyword

A constexpr (which is short for “constant expression”) variable can only be a compile-time constant.

Best practice

Any variable that should not be modifiable after initialization and whose initializer is known at compile-time should be declared as constexpr.
Any variable that should not be modifiable after initialization and whose initializer is not known at compile-time should be declared as const.

Constant folding for constant subexpressions

As an aside…

This optimization process is called “constant folding”.

4.15 — Literals

Literals are sometimes called literal constants because their values cannot be reassigned.


The type of a literal

在这里插入图片描述

Literal suffixes

If the default type of a literal is not as desired, you can change the type of a literal by adding a suffix:
在这里插入图片描述

Best practice

Prefer literal suffix L (upper case) over l (lower case).

Integral literals

Floating point literals

By default, floating point literals have a type of double. To make them float literals instead, the f (or F) suffix should be used:

#include <iostream>

int main()
{
    std::cout << 5.0; // 5.0 (no suffix) is type double (by default)
    std::cout << 5.0f; // 5.0f is type float

    return 0;
}

New programmers are often confused about why the following causes a compiler warning:

float f { 4.1 }; // warning: 4.1 is a double literal, not a float literal

Scientific notation for floating point literals

Magic numbers

Best practice

Avoid magic numbers in your code (use constexpr variables instead).

4.16 — Numeral systems (decimal, binary, hexadecimal, and octal)

Octal and hexadecimal literals

Digit separators

Digit separators are purely visual and do not impact the literal value in any way.

Outputting values in decimal, octal, or hexadecimal

4.17 — Introduction to std::string

String input with std::cin

Using strings with std::cin may yield some surprises! Consider the following example:
#include
#include

int main()
{
    std::cout << "Enter your full name: ";
    std::string name{};
    std::cin >> name; // this won't work as expected since std::cin breaks on whitespace

    std::cout << "Enter your age: ";
    std::string age{};
    std::cin >> age;

    std::cout << "Your name is " << name << " and your age is " << age << '\n';

    return 0;
}

Use std::getline() to input text

To read a full line of input into a string, you’re better off using the std::getline() function instead. std::getline() requires two arguments: the first is std::cin, and the second is your string variable.

Here’s the same program as above using std::getline():

#include <string> // For std::string and std::getline
#include <iostream>

int main()
{
    std::cout << "Enter your full name: ";
    std::string name{};
    std::getline(std::cin >> std::ws, name); // read a full line of text into name

    std::cout << "Enter your age: ";
    std::string age{};
    std::getline(std::cin >> std::ws, age); // read a full line of text into age

    std::cout << "Your name is " << name << " and your age is " << age << '\n';

    return 0;
}

What the heck is std::ws?

When you enter a value using operator>>, std::cin not only captures the value, it also captures the newline character (‘\n’) that occurs when you hit the enter key. So when we type 2 and then hit enter, std::cin captures the string “2\n” as input. It then extracts the value 2 to variable choice, leaving the newline character behind for later. Then, when std::getline() goes to extract text to name, it sees “\n” is already waiting in std::cin, and figures we must have previously entered an empty string! Definitely not what was intended.

We can amend the above program to use the std::ws input manipulator, to tell std::getline() to ignore any leading whitespace characters:

#include <string>
#include <iostream>

int main()
{
    std::cout << "Pick 1 or 2: ";
    int choice{};
    std::cin >> choice;

    std::cout << "Now enter your name: ";
    std::string name{};
    std::getline(std::cin >> std::ws, name); // note: added std::ws here

    std::cout << "Hello, " << name << ", you picked " << choice << '\n';

    return 0;
}

Best practice

If using std::getline() to read strings, use std::cin >> std::ws input manipulator to ignore leading whitespace.

Key insight

Using the extraction operator (>>) with std::cin ignores leading whitespace.
std::getline() does not ignore leading whitespace unless you use input manipulator std::ws.

std::string can be expensive to initialize and copy

Best practice

Do not pass std::string by value, as making copies of std::string is expensive. Prefer std::string_view parameters.

4.18 — Introduction to std::string_view

std::string_view C++17

Best practice

Prefer std::string_view over std::string when you need a read-only string, especially for function parameters.


constexpr std::string_view

Literals for std::string_view

#include <iostream>
#include <string>      // for std::string
#include <string_view> // for std::string_view

int main()
{
    using namespace std::literals; // easiest way to access the s and sv suffixes

    std::cout << "foo\n";   // no suffix is a C-style string literal
    std::cout << "goo\n"s;  // s suffix is a std::string literal
    std::cout << "moo\n"sv; // sv suffix is a std::string_view literal

    return 0;
};

4.x — Chapter 4 summary and quiz

The sizeof operator can be used to return the size of a type in bytes.

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 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.

Quiz time

Question #4

#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)
{
	constexpr double gravity{ 9.8 };

	// Using formula: [ s = u * t + (a * t^2) / 2 ], here u(initial velocity) = 0
	const double distanceFallen{ (gravity * (seconds * seconds)) / 2.0 };
	const 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)
{
	const double height{ calculateHeight(towerHeight, seconds) };
	printHeight(height, seconds);
}

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

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

	return 0;
}

Note that calculateHeight() doesn’t print the height itself, under the best practice that functions should do one and only one thing. We use a different function to do the printing.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值