Professional C++

Professional C++

by Marc Gregoire

Paperback(5th ed.)

View All Available Formats & Editions
Choose Expedited Shipping at checkout for delivery by Wednesday, June 23


Improve your existing C++ competencies quickly and efficiently with this advanced volume

Professional C++, 5th Edition raises the bar for advanced programming manuals. Complete with a comprehensive overview of the new capabilities of C++20, each feature of the newly updated programming language is explained in detail and with examples. Case studies that include extensive, working code round out the already impressive educational material found within.

Without a doubt, the new 5th Edition of Professional C++ is the leading resource for dedicated and knowledgeable professionals who desire to advance their skills and improve their abilities. This book contains resources to help readers:

  • Maximize the capabilities of C++ with effective design solutions
  • Master little-known elements of the language and learn what to avoid
  • Adopt new workarounds and testing/debugging best practices
  • Utilize real-world program segments in your own applications

Notoriously complex and unforgiving, C++ requires its practitioners to remain abreast of the latest developments and advancements. Professional C++, 5th Edition ensures that its readers will do just that.

Product Details

ISBN-13: 9781119695400
Publisher: Wiley
Publication date: 02/24/2021
Edition description: 5th ed.
Pages: 1312
Sales rank: 806,369
Product dimensions: 7.40(w) x 9.20(h) x 1.70(d)

About the Author

About the Author

Marc Gregoire is a Microsoft Visual C++ MVP, software architect and developer, and the founder of the Belgian C++ user group. Having previously completed critical 2G and 3G telecom software for Siemens and Nokia Siemens Networks, he currently works on X-ray, CT, and 3D geometric inspection software for Nikon Metrology. Marc is the author of Professional C++ 2nd, 3rd, and 4th editions, co-author of C++17 Standard Library Quick Reference, and technical editor for numerous published works.

Visit us at where you have access to free code samples.

Read an Excerpt

Professional C++

By Marc Gregoire Nicholas A. Solter Scott J. Kleper

John Wiley & Sons

Copyright © 2011 John Wiley & Sons, Ltd
All right reserved.

ISBN: 978-0-470-93244-5

Chapter One

A Crash Course in C++


* A brief overview of the most important parts and syntax of the C++ language

The goal of this chapter is to cover briefly the most important parts of C++ so that you have a base of knowledge before embarking on the rest of the book. This chapter is not a comprehensive lesson in the C++ programming language. The basic points (such as what a program is and the difference between = and ==) are not covered. The esoteric points (Remember what a union is? How about the volatile keyword?) are also omitted. Certain parts of the C language that are less relevant in C++ are also left out, as are parts of C++ that get in-depth coverage in later chapters.

This chapter aims to cover the parts of C++ that programmers encounter every day. For example, if you've been away from C++ for a while and you've forgotten the syntax of a for loop, you'll find that syntax in this chapter. Also, if you're fairly new to C++ and don't understand what a reference variable is, you'll learn about that kind of variable here as well.

If you already have significant experience with C++, skim this chapter to make sure that there aren't any fundamental parts of the language on which you need to brush up. If you're new to C++, read this chapter carefully and make sure you understand the examples. If you need additional introductory information, consult the titles listed in Appendix B.


The C++ language is often viewed as a "better C" or a "superset of C." Many of the annoyances or rough edges of the C language were addressed when C++ was designed. Because C++ is based on C, much of the syntax you'll see in this section will look familiar to you if you are an experienced C programmer. The two languages certainly have their differences, though. As evidence, The C++ Programming Language by C++ creator Bjarne Stroustrup (Third Edition; Addison-Wesley Professional, 2000), weighs in at 1030 pages, while Kernighan and Ritchie's The C Programming Language (Second Edition; Prentice Hall, 1988) is a scant 274 pages. So if you're a C programmer, be on the lookout for new or unfamiliar syntax!

The Obligatory Hello, World

In all its glory, the following code is the simplest C++ program you're likely to encounter.

// helloworld.cpp #include <iostream> int main() { std::cout << "Hello, World!" << std::endl; return 0; }

Code snippet from helloworld\helloworld.cpp

This code, as you might expect, prints the message "Hello, World!" on the screen. It is a simple program and unlikely to win any awards, but it does exhibit the following important concepts about the format of a C++ program.

* Comments

* Preprocessor Directives

* The main() Function

* I/O Streams

These concepts are briefly explained in the next sections.


The first line of the program is a comment, a message that exists for the programmer only and is ignored by the compiler. In C++, there are two ways to delineate a comment. In the preceding and following examples, two slashes indicate that whatever follows on that line is a comment.

// helloworld.cpp

The same behavior (this is to say, none) would be achieved by using a C-style comment, which is also valid in C++. C-style comments start with /* and end with */. In this fashion, C-style comments are capable of spanning multiple lines. The following code shows a C-style comment in action (or, more appropriately, inaction).

/* this is a multiline * C-style comment. The * compiler will ignore * it. */

Comments are covered in detail in Chapter 5.

Preprocessor Directives

Building a C++ program is a three-step process. First, the code is run through a preprocessor, which recognizes meta-information about the code. Next, the code is compiled, or translated into machine-readable object files. Finally, the individual object files are linked together into a single application. Directives aimed at the preprocessor start with the # character, as in the line #include <iostream> in the previous example. In this case, an include directive tells the preprocessor to take everything from the <iostream> header file and make it available to the current file. The most common use of header files is to declare functions that will be defined elsewhere. Remember, a declaration tells the compiler how a function is called. A definition contains the actual code for the function. The <iostream> header declares the input and output mechanisms provided by C++. If the program did not include it, it would be unable to perform its only task of outputting text.

In C, included files usually end in .h, such as <stdio.h>. In C++, the suffix is omitted for standard library headers, such as <iostream>. Your favorite standard headers from C still exist in C++, but with new names. For example, you can access the functionality from <stdio.h> by including <cstdio>.

The following table shows some of the most common preprocessor directives.

One example of using preprocessor directives is to avoid multiple includes. For example:

#ifndef MYHEADER_H #define MYHEADER_H // ... the contents of this header file #endif

If your compiler supports the #pragma once directive, this can be rewritten as follows:

#pragma once // ... the contents of this header file

Chapter 9 discusses this in more details.

The main() Function

main() is, of course, where the program starts. An int is returned from main(), indicating the result status of the program. The main() function either takes no parameters, or takes two parameters as follows:

int main(int argc, char* argv)

argc gives the number of arguments passed to the program, and argv contains those arguments. Note that the first argument is always the name of the program itself.

I/O Streams

If you're new to C++ and coming from a C background, you're probably wondering what std::cout is and what has been done with trusty old printf(). While printf() can still be used in C++, a much better input/output facility is provided by the streams library.

I/O streams are covered in depth in Chapter 15, but the basics of output are very simple. Think of an output stream as a laundry chute for data. Anything you toss into it will be output appropriately. std::cout is the chute corresponding to the user console, or standard out. There are other chutes, including std::cerr, which outputs to the error console. The << operator tosses data down the chute. In the preceding example, a quoted string of text is sent to standard out. Output streams allow multiple data of varying types to be sent down the stream sequentially on a single line of code. The following code outputs text, followed by a number, followed by more text.

std::cout << "There are " << 219 << " ways I love you." << std::endl;

std::endl represents an end-of-line sequence. When the output stream encounters std::endl, it will output everything that has been sent down the chute so far and move to the next line. An alternate way of representing the end of a line is by using the \n character. The \n character is an escape character, which refers to a new-line character. Escape characters can be used within any quoted string of text. The following table shows the most common escape characters.

Streams can also be used to accept input from the user. The simplest way to do this is to use the >> operator with an input stream. The std::cin input stream accepts keyboard input from the user. User input can be tricky because you can never know what kind of data the user will enter. See Chapter 15 for a full explanation of how to use input streams.


Namespaces address the problem of naming conflicts between different pieces of code. For example, you might be writing some code that has a function called foo(). One day, you decide to start using a third-party library, which also has a foo() function. The compiler has no way of knowing which version of foo() you are referring to within your code. You can't change the library's function name, and it would be a big pain to change your own.

Namespaces come to the rescue in such scenarios because you can define the context in which names are defined. To place code in a namespace, enclose it within a namespace block:

namespace mycode { void foo(); }

Code snippet from namespaces\namespaces.h

The implementation of a method or function can also be handled in a namespace:

#include <iostream> #include "namespaces.h" namespace mycode { void foo() { std::cout << "foo() called in the mycode namespace" << std::endl; } }

Code snippet from namespaces\namespaces.cpp

By placing your version of foo() in the namespace "mycode," it is isolated from the foo() function provided by the third-party library. To call the namespace-enabled version of foo(), prepend the namespace onto the function name by using :: also called the scope resolution operator as follows.

mycode::foo(); // Calls the "foo" function in the "mycode" namespace

Any code that falls within a "mycode" namespace block can call other code within the same namespace without explicitly prepending the namespace. This implicit namespace is useful in making the code more precise and readable. You can also avoid prepending of namespaces with the using directive. This directive tells the compiler that the subsequent code is making use of names in the specified namespace. The namespace is thus implied for the code that follows:

#include "namespaces.h" using namespace mycode; int main() { foo(); // Implies mycode::foo(); return 0; }

Code snippet from namespaces\usingnamespaces.cpp

A single source file can contain multiple using directives, but beware of overusing this shortcut. In the extreme case, if you declare that you're using every namespace known to humanity, you're effectively eliminating namespaces entirely! Name conflicts will again result if you are using two namespaces that contain the same names. It is also important to know in which namespace your code is operating so that you don't end up accidentally calling the wrong version of a function.

You've seen the namespace syntax before — you used it in the Hello, World program, where cout and endl are actually names defined in the std namespace. You could have written Hello, World with the using directive as shown here:

#include <iostream> using namespace std; int main() { cout << "Hello, World!" << endl; return 0; }

The using directive can also be used to refer to a particular item within a namespace. For example, if the only part of the std namespace that you intend to use is cout, you can refer to it as follows:

using std::cout;

Subsequent code can refer to cout without prepending the namespace, but other items in the std namespace will still need to be explicit:

using std::cout; cout << "Hello, World!" << std::endl;


In C++, variables can be declared just about anywhere in your code and can be used anywhere in the current block below the line where they are declared. Variables can be declared without being given a value. These uninitialized variables generally end up with a semi random value based on whatever is in memory at the time and are the source of countless bugs. Variables in C++ can alternatively be assigned an initial value when they are declared. The code that follows shows both flavors of variable declaration, both using ints, which represent integer values.

int uninitializedInt; int initializedInt = 7; cout << uninitializedInt << " is a random value" << endl; cout << initializedInt << " was assigned an initial value" << endl;

Code snippet from hellovariables\hellovariables.cpp

When run, this code will output a random value from memory for the first line and the number 7 for the second. This code also shows how variables can be used with output streams.

Most compilers will issue a warning when code is using uninitialized variables, and some C++ environments may report a run time error when uninitialized variables are being accessed.

The table that follows shows the most common variable types used in C++.

C++ does not provide a basic string type. However, a standard implementation of a string is provided as part of the standard library as described later in this chapter and in Chapter 14.

Variables can be converted to other types by casting them. For example, an int can be cast to a bool. C++ provides three ways of explicitly changing the type of a variable. The first method is a holdover from C, but is still the most commonly used. The second method seems more natural at first but is rarely seen. The third method is the most verbose, but often considered the cleanest.

bool someBool = (bool)someInt; // method 1 bool someBool = bool(someInt); // method 2 bool someBool = static_cast<bool>(someInt); // method 3

The result will be false if the integer was 0 and true otherwise. Chapter 9 describes the different casting methods in more detail. In some contexts, variables can be automatically cast, or coerced. For example, a short can be automatically converted into a long because a long represents the same type of data with additional precision.

long someLong = someShort; // no explicit cast needed

When automatically casting variables, you need to be aware of the potential loss of data. For example, casting a float to an int throws away information (the fractional part of the number). Many compilers will issue a warning if you assign a float to an int without an explicit cast. If you are certain that the left-hand side type is fully compatible with the right-hand side type, it's okay to cast implicitly.


What good is a variable if you don't have a way to change it? The following table shows the most common operators used in C++ and sample code that makes use of them. Note that operators in C++ can be binary (operate on two variables), unary (operate on a single variable), or even ternary (operate on three variables). There is only one ternary operator in C++ and it is covered in the section "Conditionals."

The following program shows the most common variable types and operators in action. If you're unsure about how variables and operators work, try to figure out what the output of this program will be, and then run it to confirm your answer.

#include <iostream> using namespace std; int main() { int someInteger = 256; short someShort; long someLong; float someFloat; double someDouble;

someInteger++; someInteger *= 2; someShort = (short)someInteger; someLong = someShort * 10000; someFloat = someLong + 0.785; someDouble = (double)someFloat / 100000; cout << someDouble << endl; return 0; }

Code snippet from typetest\typetest.cpp

The C++ compiler has a recipe for the order in which expressions are evaluated. If you have a complicated line of code with many operators, the order of execution may not be obvious. For that reason, it's probably better to break up a complicated statement into several smaller statements or explicitly group expressions by using parentheses. For example, the following line of code is confusing unless you happen to know the C++ operator precedence table by heart:

int i = 34 + 8 * 2 + 21 / 7 % 2;

Adding parentheses makes it clear which operations are happening first:

int i = 34 + (8 * 2) + ( (21 / 7) % 2 );

Breaking up the statement into separate lines makes it even clearer:

int i = 8 * 2; int j = 21 / 7; j %= 2; i = 34 + i + j;

For those of you playing along at home, all three approaches are equivalent and end up with i equal to 51. If you assumed that C++ evaluated expressions from left to right, your answer would have been 1. In fact, C++ evaluates /, *, and % first (in left-to-right order), followed by addition and subtraction, then bitwise operators. Parentheses let you explicitly tell the compiler that a certain operation should be evaluated separately.


In C++, you can use the basic types (int, bool, etc.) to build more complex types of your own design. Once you are an experienced C++ programmer, you will rarely use the following techniques, which are features brought in from C, because classes are far more powerful. Still, it is important to know about the two most common ways of building types so that you will recognize the syntax.


Excerpted from Professional C++ by Marc Gregoire Nicholas A. Solter Scott J. Kleper Copyright © 2011 by John Wiley & Sons, Ltd. Excerpted by permission of John Wiley & Sons. All rights reserved. No part of this excerpt may be reproduced or reprinted without permission in writing from the publisher.
Excerpts are provided by Dial-A-Book Inc. solely for the personal use of visitors to this web site.

Table of Contents

Introduction xlvii

Part I: Introduction to Professional C++

Chapter 1: A Crash Course In C++ And The Standard Library 3

Chapter 2: Working With Strings And String Views 87

Chapter 3: Coding With Style 111

Part II: Professional C++ Software Design

Chapter 4: Designing Professional C++ Programs 137

Chapter 5: Designing With Objects 169

Chapter 6: Designing For Reuse 187

Part III: C++ Coding the Professional Way

Chapter 7: Memory Management 211

Chapter 8: Gaining Proficiency With Classes And Objects 249

Chapter 9: Mastering Classes and Objects 283

Chapter 10: Discovering Inheritance Techniques 337

Chapter 11: Odds and Ends 397

Chapter 12: Writing Generic Code With Templates 421

Chapter 13: Demystifying C++ I/O 465

Chapter 14: Handling Errors 495

Chapter 15: Overloading C++ Operators 535

Chapter 16: Overview of The C++ Standard Library 573

Chapter 17: Understanding Iterators and The Ranges Library 603

Chapter 18: Standard Library Containers 627

Chapter 19: Function Pointers, Function Objects, And Lambda Expressions 699

Chapter 20: Mastering Standard Library Algorithms 725

Chapter 21: String Localization and Regular Expressions 763

Chapter 22: Date and Time Utilities 793

Chapter 23: Random Number Facilities 809

Chapter 24: Additional Library Utilities 821

Part IV: Mastering Advanced Features of C++

Chapter 25: Customizing and Extending The Standard Library 833

Chapter 26: Advanced Templates 877

Chapter 27: Multithreaded Programming With C++ 915

Part V: C++ Software Engineering

Chapter 28: Maximizing Software Engineering Methods 971

Chapter 29: Writing Efficient C++ 993

Chapter 30: Becoming Adept at Testing 1021

Chapter 31: Conquering Debugging 1045

Chapter 32: Incorporating Design Techniques and Frameworks 1083

Chapter 33: Applying Design Patterns 1105

Chapter 34: Developing Cross-Platform and Crosslanguage Applications 1137

Part VI: Appendices

Appendix A: C++ Interviews 1165

Appendix B: Annotated Bibliography 1191

Appendix C: Standard Library Header Files 1203

Appendix D: Introduction to UML 1213

Index 1219

Customer Reviews