The C++ Programming Language Notes

Table of Contents

Overview

Preface

A programmer can partition an application into manageable pieces by defining new types that closely match the concepts of the application. This technique for program construction is often called data abstraction.

Objects of some user-defined types contain type information. Programs using objects of such types are often called object based.

Chapter 1 Notes to the Reader

1.3.1

Except for the new, delete, typeid, dynamic_cast, and throw operators and the try-block, individual C++ expression and statements need no run-time support.

1.6.1 Suggestions for C Programmers

  1. Macros are almost never necessary in C++. Use c o n s t (§5.4) or e n u m (§4.8) to define manifest constants, i n l i n e (§7.1.1) to avoid function-calling overhead, t e m p l a t e s (Chapter 13) to specify families of functions and types, and n a m e s p a c e s (§8.2) to avoid name clashes.
  2. Don’t declare a variable before you need it so that you can initialize it immediately. A declaration can occur anywhere a statement can (§6.3.1), in for-statement initializers (§6.3.3), and in conditions (§6.3.2.1).
  3. Don’t use malloc(). The n e w operator (§6.2.6) does the same job better, and instead of r e a l l o c (), try a v e c t o r (§3.8).
  4. Try to avoid v o i d *, pointer arithmetic, unions, and casts, except deep within the implementation of some function or class. In most cases, a cast is an indication of a design error. If you must use an explicit type conversion, try using one of the ‘‘new casts’’ (§6.2.7) for a more precise statement of what you are trying to do.
  5. Minimize the use of arrays and C-style strings. The C++ standard library s t r i n g (§3.5) and v e c t o r (§3.7.1) classes can often be used to simplify programming compared to traditional C style. In general, try not to build yourself what has already been provided by the standard library.

1.8 Advice

  1. When you program, you create a concrete representation of the ideas in your solution to some problem. Let the structure of the program reflect those ideas as directly as possible:

[a] If you can think of ‘‘it’’ as a separate idea, make it a class.
[b] If you can think of ‘‘it’’ as a separate entity, make it an object of some class.
[c] If two classes have a common interface, make that interface an abstract class.
[d] If the implementations of two classes have something significant in common, make that commonality a base class.
[e] If a class is a container of objects, make it a template.
[f] If a function implements an algorithm for a container, make it a template function implementing the algorithm for a family of containers.
[g] If a set of classes, templates, etc., are logically related, place them in a common namespace.

  1. When you define either a class that does not implement either a mathematical entity like a matrix or a complex number or a low-level type such as a linked list:

[a] Don’t use global data (use members).
[b] Don’t use global functions.
[c] Don’t use public data members.
[d] Don’t use friends, except to avoid [a] or [c].
[e] Don’t put a ‘‘type field’’ in a class; use virtual functions.
[f] Don’t use inline functions, except as a significant optimization.

Chapter 2 A Tour of C++

2.5.4 Abstract Types

class Stack{
public:
  virtual void push(char c) = 0;
  virtual char pop() = 0;
};

The word virtual means "may be redefined later in a class derived from this one" in Simula and C++.

The curious =0 syntax says that some class derived from Stack must define the function.

2.7.1 Containers

A class holding a collection of elements of some type is commonly called a container class, or simply a container.

Templates are a compile-time mechanism so that their use incurs no run-time overhead compared to ‘‘handwritten code.’’

Chapter 3 A Tour of the Standard Library

3.5.1 CStyle Strings

To call functions that take C-style strings, we need to be able to extract the value of a string in the form of a C-style string. The c_str() function does that.

3.7 Containers

A class with the main purpose of holding objects is commonly called a container.

  • 3.7.3 List

    Every standard library container provides the functions begin() and end(), which return an iterator to the first and to one-past-the-last element, respectively (§16.3.2).

    When we don’t need to modify an element of the container, const_iterator is the type we want. Otherwise, we use the plain iterator type (§16.3.1).

  • 3.7.5 Standard Containers

    Standard Container Summary
    vecotr<T> A variable-sized vector (§16.3)
    list<T> A doubly-linked list (§17.2.2)
    queue<T> A queue (§17.3.2)
    stack<T> A stack (§17.3.1)
    deque<T> A double-ended queue (§17.2.3)
    priority queue<T> A queue sorted by value (§17.3.3)
    set<T> A set (§17.4.3)
    multiset<T> A set in which a value can occur many times (§17.4.4)
    map<key,val> An associative array (§17.4.1)
    multimap<key,val> A map in which a key can occur many times (§17.4.2)

3.8

  • 3.8.2 Iterator Types

    Any particular iterator is an object of some type. There are, however, many different iterator types because an iterator needs to hold the information necessary for doing its job for a particular container type. These iterator types can be as different as the containers and the specialized needs they serve.

    In fact, any object that obeys a few simple rules like these is an iterator (§19.2.1).

  • 3.8.4 Traversals and Predicates
    bool gt_42(const pair<const string, int>& r)
    {
      return r.second > 42;
    }
    
    void g(const map<string, int>& m)
    {
      int c42 = conunt_if(m.begin(), m.end(), gt_42);
    }
    

    A function, such as gt42(), that is used to control the algorithm is called a predicate. A predicate is called for each element and returns a Boolean value, which the algorithm uses to perform its intended action.

    void g(list<Shape *>& sh)
    {
      for_each(sh.begin(), sh.end(), mem_fun(&Shape::draw));
    }
    

    The standard library memfun() template (§18.4.4.2) takes a pointer to a member function (§15.5) as its argument and produces something that can be called for a pointer to the member’s class. The result of memfun (&Shape::draw) takes a Shape * argument and returns whatever Shape::draw() returns.

  • 3.8.6 Standard Library Algorithms

    The algorithms are defined in namespace std and presented in the <algorithm> header. Here are a few I have found particularly useful:

     Selected Standard Algorithms
    foreach() Invoke function for each element (§18.5.1)
    find() Find first occurrence of arguments (§18.5.2)
    findif() Find first match of predicate (§18.5.2)
    count() Count occurrences of element (§18.5.3)
    countif() Count matches of predicate (§18.5.3)
    replace() Replace element with new value (§18.6.4)
    replaceif() Replace element that matches predicate with new value (§18.6.4)
    copy() Copy elements (§18.6.1)
    uniquecopy() Copy elements that are not duplicates (§18.6.1)
    sort() Sort elements (§18.7.1)
    equalrange() Find all elements with equivalent values (§18.7.2)
    merge() Merge sorted sequences (§18.7.3)

3.11 Advice

[2] Don’t believe in magic; understand what your libraries do, how
they do it, and at what cost they do it.
[7] Use string rather than char *; §3.5, §3.6.
[12] Catch common exceptions in main(); §3.7.2.

Chapter 4 Types and Declarations

4.2 Booleans

A pointer can be implicitly converted to a bool. A nonzero pointer converts to true; zero valued pointers convert to false.

4.3 Character Types

The possibility of converting a char to an integer raises the question: is a char signed or unsigned?

The 256 values represented by an 8bit byte can be interpreted as the values 0 to 255 or as the values 127 to 127. Unfortunately, which choice is made for a plain char is implementation-defined (§C.1, §C.3.4).

A type wchar_t is provided to hold characters of a larger character set such as Unicode.

  • 4.3.1 Character Literals

    Wide character literals are of the form L´ab´, where the number of characters between the quotes and their meanings is implementation-defined to match the wchar_t type.

4.4 Integer Types

Unlike plain char s, plain int s are always signed.

  • 4.4.1 Integer Literals

    The suffix U can be used to write explicitly unsigned literals. Similarly, the suffix L can be used to write explicitly long literals. For example, 3 is an int , 3U is an unsigned int , and 3L is a long int.

  • 4.5.1 Floating-Point Literals

    By default, a floating-point literal is of type double.

    If you want a floating-point literal of type float, you can define one using the suffix f or F :

    3.14f 2.0f 1.99F

4.6 Sizes

When needed, implementation-dependent aspects about an implementation can be found in <limits>

#include <limits>

int main()
{
  cout << "largest float == " << numeric_limits<float>::max()
       << ", char is signed == " << numeric_limits<char>::is_signed << '\n';
}

4.8 Enumerations

The range of an enumeration holds all the enumeration’s enumerator values rounded up to the nearest larger binary power minus 1 . The range goes down to 0 if the smallest enumerator is non-negative

enum e1 { dark, light };          //range 0:1
enum e2 { a = 3, b = 9 };         //range 0:15
enum e3 { min = -10, max = 1000000 }; //range: -1048576:1048575

A value of integral type may be explicitly converted to an enumeration type. The result of such a conversion is undefined unless the value is within the range of the enumeration.

enum flag { x = 1, y = 2, z = 4, e = 8 }; //range 0:15
flag f1 = 5;   //type error: 5 is not of type flag
flag f2 = flag(5); //ok: flag(5) is of type flag and within the range of flag

By default, enumerations are converted to integers for arithmetic operations (§6.2). An enumeration is a user-defined type, so users can define their own operations, such as ++ and << for an enumeration (§11.2.3).

4.9

  • 4.9.1 The Structure of a Declaration

    The postfix declarator operators bind tighter than the prefix ones. Consequently, *kings[] is a vector of pointers to something, and we have to use parentheses to express types such as ‘‘pointer to function;’’

  • 4.9.4 Scope

    A hidden global name can be referred to using the scope resolution operator ::.

    int x;
    
    void f2()
    {
      int x = 1; //hide global x
      ::x = 2;  //assign to globlal x
      x = 2;   //assign to local x
    }
    
  • 4.9.5 Initialization

    If no initializer is specified, a global (§4.9.4), namespace (§8.2), or local static object (§7.1.2, §10.2.4) (collectively called static objects) is initialized to 0 of the appropriate type.

  • 4.9.6 Objects and Lvalues

    That is, an object is a contiguous region of storage; an lvalue is an expression that refers to an object.

4.10 Advice

[4] Keep common and local names short, and keep uncommon and nonlocal names longer; §4.9.3.
[5] Avoid similar-looking names; §4.9.3.
[6] Maintain a consistent naming style; §4.9.3.
[9] Use typedef s to define synonyms for types; use enumerations and classes to define new types;
[18] Avoid unsigned arithmetic; §4.4.
[19] View signed to unsigned and unsigned to signed conversions with suspicion; §C.6.2.6.
[20] View floatin-gpoint to integer conversions with suspicion; §C.6.2.6.
[21] View conversions to a smaller type, such as int to char , with suspicion; §C.6.2.6.

Chapter 5 Pointers, Arrays, and Structures

5.1 Pointers

The fundamental operation on a pointer is dereferencing, that is, referring to the object pointed to by the pointer. This operation is also called indirection.

  • 5.1.1 Zero

    Zero (0) is an int. Because of standard conversions (§C.6.2.3), 0 can be used as a constant of any integral (§4.1.1), floating-point, pointer, or pointer-to-member type. The type of zero will be determined by context.

    In C, it has been popular to define a macro NULL to represent the zero pointer. Because of C++’s tighter type checking, the use of plain 0 , rather than any suggested NULL macro, leads to fewer problems.

5.2 Arrays

The number of elements of the array, the array bound, must be a constant expression. If you need variable bounds, use a vector.

void f(int i)
{
  int v1[i];     //error: array size not a constant expression
  vector<int> v2[i]; // ok
}
  • 5.2.1 Array Initializers

    If the initializer supplies too few elements, 0 is assumed for the remaining array elements. For example:

    char v5[8] = { 1, 2, 3, 4};
    is equivalent to
    char v5[8] = { 1, 2, 3, 4, 0, 0, 0, 0};
    
  • 5.2.2 String Literals

    Whether two identical character literals are allocated as one is implementation-defined. For example:

    const char* p = "Heraclitus";
    const char* q = "Heraclitus";
    
    void g()
    {
      if(p == q) cout<< "one \n"; //result is implementation-defined
      //..
    }
    

    The empty string is written as a pair of adjacent double quotes, "", (and has the type const char[1]).

    A string with the prefix L, such as L"angst" , is a string of wide characters (§4.3, §C.3.3). Its type is wchar_t[].

5.3 Pointers into Arrays

The implicit conversion of the array argument to a pointer means that the size of the array is lost to the called function.

  • 5.3.1 Navigating Arrays

    This implies that the integer value of p+1 will be sizeof(T) larger than the integer value of p .

5.4 Constants

const int c1 = 1;

The simple and common case is the one in which the value of the constant is known at compile time and no storage needs to be allocated; c1 is an example of that.

  • 5.4.1 Pointers and Constants

    ‘‘Prefixing’’ a declaration of a pointer with const makes the object, but not the pointer, a constant. To declare a pointer itself, rather than the object pointed to, to be a constant, we use the declarator operator *const instead of plain *.

    The declarator operator that makes a pointer constant is *const. There is no const * declarator operator, so a const appearing before the * is taken to be part of the base type. For example:

    char *const cp;     //const pointer to char
    char const* pc;     //pointer to const char
    const char* pc2;    //pointer to const char
    

    Some people find it helpful to read such declarations right-to-left. For example, ‘‘cp is a const pointer to a char ’’ and ‘‘pc2 is a pointer to a char const.’’

5.5 References

The initializer for a ‘‘plain’’ T & must be an lvalue of type T . The initializer for a const T& need not be an lvalue or even of type T . In such cases,

  • [1] first, implicit type conversion to T is applied if necessary (see §C.6);
  • [2] then, the resulting value is placed in a temporary variable of type T ; and
  • [3] finally, this temporary variable is used as the value of the initializer.
double& dr = 1;          //error: lvalue needed
const double& cdr = 1;   //ok

The interpretation of this last initialization might be:

double temp = double(1);  //first create a temporary with the right value
const double& cdr = temp; //then use the temporary as the intializer for cdr

5.7 Structures

The name of a type becomes available for use immediately after it has been encountered and not just after the complete declaration has been seen. For example:

struct Link{
  Link* previous;
  Link* successor;
};

It is not possible to declare new objects of a structure type until the complete declaration has been seen. For example:

struct No_good{
  No_good member;  //error: recursive definition
};

This is an error because the compiler is not able to determine the size of N o _ g o o d .

Chapter 6 Expressions and Statements

Chapter 7 Functions

Chapter 8 Namespaces and Exceptions

Chapter 9 Source Files and Programs

Chapter 10 Classes

Chapter 11 Operator Overloading

Chapter 12 Derived Classes

Chapter 13 Templates

Chapter 14 Exceptions Handling

Chapter 15 Class Hierarchies

Chapter 16 Library Organization and Containers

Chapter 17 Standard Containers

Chapter 18 Algorithms and Function Objects

Chapter 19 Iterators and Allocators

Chapter 20 Strings

Chapter 21 Streams

Chapter 22 Numerics

Chapter 23 Developing and Design

Chapter 24 Design and Programming

Chapter 25 Roles of Classes

Appendix A

Appendix B

Appendix C

Author: Shi Shougang

Created: 2015-03-05 Thu 23:21

Emacs 24.3.1 (Org mode 8.2.10)

Validate