Author:Xiang He
August 28, 2018
1 Basic ideas
1 e x p l i c i t Account ( std : : s t r i n g accountName ) 2 : name{accountName} { // member i n i t i a l i z e r 3 // empty body 4 }
Constructor: Initialize data members when an object is created. Regard it as a member function
withpublicaccess identifier.
Keyword explicit: it takes single parameter (will go into more details later).
Constructor cannot return values and cannot be declared const (because initializing an object mod-
ifies it).
In any class that does not explicitly define a constructor, the compiler provides a default constructor
with no parameters. The default constructor does not initialize the class’s fundamental-type data
members, but does call the default constructor for each data member that’s an object of another
class. But if a custom constructor for a class is defined, the compiler will not create a default
constructor for that class. In that case, the parameters must be passed to the constructor.
C++11 allows you to force the compiler to create the default constructor even if you’ve defined
non-default constructors.
setfunctions can be programmed to validate their arguments and reject any attempts tosetthe
data to bad values. Agetfunction can present the data in a different form, while the actual data
representation remains hidden from the user. From this way to protect the private data members.
getline function: from the< string >header, reads characters up to, but not including, a newline,
which is discarded, then places the characters in a string.
C++ ’s only ternary operator: ?:, can replace the if-else statement. The values in a conditional
expression also can be actions to execute.
staticcast operator: explicitly perform a conversion between fundamental types.
1 double average{s t a t i c c a s t
The value stored intotalis still an integer.
setprecision(argument): parameterized stream manipulator from< iomanip >. It requires a argu- ment to perform its task.
fixed: nonparameterized stream manipulator (such as endl). It indicates that floating-point values should be output infixed-point format, as opposed toscientific notation(Without the fixed-point formatting option, 88.00 prints as 88 without the trailing zeros and decimal point).
When the stream manipulators fixed and setprecision are used, the printed value isroundedto the number of decimal positions indicated by setprecision ’s argument.
C++ fundamental types are not portable across different platforms (e.g.,int 32 andint 64 ).
setw(argument): paramterized stream manipulator which specifies that the next value output should appear in a field width of theargument. Right justified by default.
C++ does not have an exponentiation operator (Python has **). pow(x, y) from< cmath > calculates the value ofxraised to theyth power.
Short circuit evaluation: The parts of an expression containing && or||operators are evaluated only until it’s known whether the condition is true or false.
A function prototype is required unless the function is defined before it’s used.
Argument coercion: force arguments to the appropriate types specified by the parameter declarations.
Figure 1: Promotion hierarchy for arithmetic data types
Converting values to lower fundamental types can cause errors due to narrowing conversions. There- fore, a value can be converted to a lower fundamental type only byexplicitlyassigning the value to
a variable of lower type or by using a cast operator.
Scaling and shifting random numbers:
type variableN ame{shif tingV alue+rand() %scalingF actor}
where theshif tingV alueis equal to the first number in the desired range of consecutive integers
and thescalingF actoris equal to the width of the desired range of consecutive integers.
Generate random numbers without having to enter a seed each time:
1 srand ( s t a t i c c a s t
All static local variables of numeric types are initialized to zero by default. A static local variable
retains its value when the function returns to its caller. The next time the function is called, the
static local variable contains the value it had when the function last completed execution.
Except for truly global resources such ascinandcout, global variables should be avoided.
pass by value: a copy of the argument’s value is made and passed (on the function-call stack) to
the called function. Changes to the copy do not affect the original variable’s value in the caller.
pass by reference with &: the caller gives the called function the ability to access the caller’s data
directly, and to modify that data. It can eliminate the pass-by-value overhead of copying large
amounts of data. Reference variables must be initialized in their declarations and cannot be reas-
signed as aliases to other variables.
For passing large objects, use a const reference parameter to simulate the appearance and
security of pass-by-value and avoid the overhead of passing a copy of the large object.
Returning references to local variables can be dangerous.
C++ provides the unary scope resolution operator (::) to access a global variable when a local
variable of the same name is in scope. This is also used to access the members of class.
2 Function Overloading
C++ enables several functions of the same name to be defined, as long as they have different sig-
natures. The C++ compiler selects the proper function to call by examining thenumber, types
and order of the argumentsin the call.
Overloaded functions can have different return types, but if they do, they must also have different
parameter lists.
If the program logic and operations are identical for each data type, overloading may be performed
more compactly and conveniently by using function templates. C++ automatically generates sep-
arate function template specializations to handle each type of call appropriately. Thus, defining a
single function template essentially defines a whole family of overloaded functions.
1 template
Recursion has negatives. It repeatedly invokes the mechanism, and consequently the overhead, of
function calls. This can be expensive in both processor time and memory space. Each recursive call
causes another copy of the function variables to be created; this can consume considerable memory.
Avoid using recursion!
Recursion example: Fibonacci Series.
1 // r e c u r s i v e f u n c t i o n f i b o n a c c i
2 unsigned long f i b o n a c c i ( unsigned long number ) {
3 i f ((0 == number ) || (1 == number ) ) { // base cases
4 r e t u r n number ;
5 }
6 e l s e { // r e c u r s i o n step
7 r e t u r n f i b o n a c c i ( number− 1) + f i b o n a c c i ( number− 2) ;
8 }
9 }
C++ does not specify the order in which the operands of most operators (including + ) are to be
evaluated. C++ specifies the order of evaluation of the operands of only four operators – && ,||
, comma ( , ) and ?:. The first three are binary operators whose two operands are guaranteed to
be evaluated left to right. The last operator is C++’s only ternary operator—its leftmost operand
is always evaluated first; if it evaluates to true, the middle operand evaluates next and the last
operand is ignored; if the leftmost operand evaluates to false, the third operand evaluates next and
the middle operand is ignored.
3 Array and Vector
array is from< array >header. sizet is always used for the index of arrays.
For instance:
1 const s i z e t a r r a y S i z e{ 10 }; 2 array <int , arraySize> grade{} // a l l i n i t i a l i z e d to zero
We can apply static to a local array declaration so that it’s not created and initialized each time the
program calls the function and is not destroyed each time the function terminates. This can improve
performance, especially when using large arrays.
C and C++ also have bulit-in array, but it has a lot of limitations:
- They cannot be compared using the relational and equality operators—you must use a loop to compare two built-in arrays element by element.
- They cannot be assigned to one another—an array name is effectively a pointer that is const.
- They don’t know their own size—a function that processes a built-in array typically receives both the built-in array’s name and its size as arguments.
- They don’t provide automatic bounds checking—you must ensure that array-access expressions use subscripts that are within the built-in array’s bounds. The value of a built-in array’s name is implicitly convertible to the address of the built-in array’s first element, so you don’t need to take the address ( & ) of a built-in array to pass it to a function—you simply pass the built-in array’s name. As pass-by-reference, the called function can modify all the elements of a built-in array in the caller—unless the function precedes the corresponding built-in array parameter with const to indicate that the elements should not be modified.
Declare a built-in array parameter in a function header:
1 i n t sumElements ( const i n t v a l u e s [ ] , const s i z e t numberOfElements )
which is equivalent to:
1 i n t sumElements ( const i n t∗ values , const s i z e t numberOfElements )
Vector supports dynamic resizing.
Pointer comparisons compare the addresses stored in the pointers. A common use of pointer com-
parison is determining whether a pointer has the value nullptr , 0 or NULL.
4 Class: A Deeper Look
Client code can access a class’s public members via:
- the name of an object and the dot operator (.);
- a reference to an object and the dot operator (.);
- a pointer to an object and the arrow operator (−>).
Two important C++ software engineering concepts:
- Separating interface from implementation;
- Using an include guard in a header to prevent the header code from being included into the same source code file more than once. Since a class can be defined only once, using such preprocessing directives prevents multiple-definition errors.
For the first concept, just put the definition of class in the header file, and put the implementation
into the corresponding.cppfile. In this situation, every member function in the.cppfile must with
theclass name and the scope resolution operator (::) in front of it. Or they will be compiled
as global functions and cannot access the private data members in the class.
For the second concept, put the below code into the header file:
1 #i f n d e f TIMEH 2 #d e f i n e TIMEH 3… // the d e f i n i t i o n of c l a s s 4 #e n d i f
Objects of class ostringstream (from the header< sstream >) provide the same functionality with
cout, but write their output to string objects in memory. You use class ostringstream’s str member
function to get the formatted string. For instance:
1 s t r i n g Time : : t o U n i v e r s a l S t r i n g () const { 2 o s t r i n g s t r e a m output ; 3 output« s e t f i l l ( ’ 0 ’ )« setw (2)« hour «” : ” 4 « setw (2)« minute«” : ”« setw (2)«second ; 5 r e t u r n output. s t r () ; // r e t u r n s the formatted s t r i n g 6 }
Parameterized stream manipulator is used setfill to specify the fill character that’s displayed when
an integer is output in a field wider than the number of digits in the value. Once the fill character
is specified with setfill, it applies for all subsequent values that are displayed in fields wider than the
value being displayed - setfill is a sticky setting.
If a member function is defined in a class’s body, the member function is implicitly declared inline
(if the compiler chooses to do so), and this can improve the performance.
Destructor, begins with tilde character followed by the class name, is the complement of constructor.
The destructor itself does not actually release the object’s memory when it is destroyed – it performs
termination housekeeping before the object’s memory is reclaimed, so the memory may be reused
to hold new objects.
Destructors are not called for (non-static) local objects if the program terminates with a call to
functionexitor functionabort.
The constructor for astaticlocal object is called only once, when execution first reaches the point
where the object is defined – the corresponding destructor is called when main terminates or the
program calls functionexit. Destructors are not called forstaticobjects if the program terminates
with a call to functionabort.
Return a reference or a pointer to the private data members in member functions is dangerous since
it enables clients of the class to clobber the class’s private data at will.
C++ disallows member-function calls forconstobjects unless the member functions themselves are
also declaredconst.
A constructor must be a non-constmember function, but it can still be used to initialize aconst
object. Invoking a non-constmember function from the constructor call as part of the initialization
of aconstobject is allowed.
A friend function of a class is a non-member function that has the right to access the public and
non-public class members. Standalone functions, entire classes or member functions of other classes
may be declared to be friends of another class.
this pointer is an implicit parameter to all member functions. Therefore, inside a member function,
this may be used to refer to the invoking object. friend functions do not have a this pointer, because
friends are not members of a class.
1 // s e t hour value 2 void Time : : setHour ( i n t hour ) { 3 i f ( hour>= 0 && hour< 24) { 4 thi s−>hour = hour ; // use this−> to access data member 5 } 6 e l s e { 7 throw i n v a l i d a r g u m e n t ( ” hour must be 0−23” ) ; 8 } 9 }
The type of the this pointer depends on the type of the object and whether the member function in
which this is used is declared const:
- In a non-const member function of class Employee, the this pointer has the typeEmployee* const– a constant pointer to a nonconstant Employee.
- In a const member function, this has the typeconst Employee* const– a constant pointer to a constant Employee.
5 Operator Overloading & Class String
Normally, when you output a condition’s value 0 is displayed for false or 1 for true. With stream
manipulator boolalpha, condition values can be displayed as ”true” and ’false”.
When overloading (), [ ],−>or any of the assignment operators, the operator overloading function
must be declared as a class member. For all other overloadable operators, the operator overloading
functions can be member functions or non-member functions.
Overloaded operator functions for binary operators can be member functions only when the left
operand is an object of the class in which the function is a member. Thus, the overloading for input
and output stream operators<<and>>should be declared as non-member friend functions.
A unary operator for a class can be overloaded as a non-static member function with no arguments
or as a non-member function with one argument that must be an object (or a reference to an object)
of the class.
The postfix increment operator typically returns a temporary object that contains the original value
of the object before the increment occurred. C++ treats such objects asrvalues, which cannot be
used on the left side of an assignment. The prefix increment operator returns the actual incremented
object with its new value. Such an object can be used as anlvaluein a continuing expression. The
extra object that’s created by the postfix increment (or decrement) operator can result in a perfor-
mance problem—especially when the operator is used in a loop. For this reason, we should prefer
the overloaded prefix increment and decrement operators.
You can use thenewoperator to dynamically allocate (i.e., reserve) the exact amount of memory
required to hold an object or built-in array at execution time. The object or built-in array is created
in thefree store(also called theheap) - a region of memory assigned to each program for storing
dynamically allocated objects. Once memory is allocated, you can access it via the pointer returned
by operatornew. When you no longer need the memory, you can return it to the free store by using
thedeleteoperator to deallocate (i.e., release) the memory, which can then be reused by future
newoperations.
1 double∗ ptr{new double{3.14159}}; 2 Time∗ timePtr{new Time{12 , 45 , 0}}; 3 i n t∗ gradesArray{new i n t [ 1 0 ]{}}; 4 5 d e l e t e [ ] gradesArray ;
The size of a built-in array created at compile time must be specified using an integral constant
expression; however, a dynamically allocated array’s size can be specified using any nonnegative
integral expression that can be evaluated at execution time.
The compiler cannot know in advance how to convert among user-defined types, and between user-
defined types and fundamental types, so you must specify how to do this. Such conversions can be
performed withconversion constructors- single-argument constructors that turn objects of other
types (including fundamental types) into objects of a particular class. A constructor that can be
called with a single argument can be used as aconversion constructor. Aconversion operator
must be a non-static member function.
The reason we’ve been declaring every single-argument constructor preceded by the keyword explicit
is to suppress implicit conversions via conversion constructors when such conversions should not be
allowed. A constructor that’s declared explicit cannot be used in an implicit conversion.
6 Inheritance
Figure 2:public,protectedandprivateinheritance comparison
When an object of a derived class is instantiated, the base class’s constructor is called immediately to initialize the base-class data members in the derived-class object, then the derived-class constructor initializes the additional derived-class data members.
When a derived-class object is destroyed, the destructors are called in the reverse order of the con- structors—first the derived-class destructor is called, then the base-class destructor is called.
A base class’spublicmembers are accessible anywhere that the program has a handle to an object of that base class or to an object of one of that base class’s derived classes.
A base class’sprivatemembers are accessible only within the base class or from its friends.
A base class’sprotectedmembers can be accessed by members and friends of that base class and by members and friends of any classes derived from that base class.
Declaring base-class data membersprivate(as opposed to declaring themprotected) enables you
to change the base-class implementation without having to change derived-class implementations.
When a base-class member function is redefined in a derived class, the derived-class version often
calls the base-class version to do additional work. Failure to use the :: operator prefixed with the
name of the base class when referencing the base class’s member function causes infinite recursion,
because the derived-class member function would then call itself.
By default, base-class constructors, destructors and overloaded assignment operators are not inher-
ited by derived classes. Derived-class constructors, destructors and overloaded assignment operators,
however, can call base-class versions.
In C++11, a derived class can inherit constructors from its base class by including anywhere in the
derived-class definition a using declaration of the form
1 using BaseClass : : BaseClass ;
In this case, the base-class constructor’s default arguments are not inherited.
7 Polymorphism
Polymorphism enables us to write programs that process objects of classes that are part of the same
class hierarchy as if they were all objects of the hierarchy’s base class.
The type of the handle (pointer and reference) determines which function is called (rather than the
type of the object). When we attempt to invoke derived-class-only member functions through the
base-class pointer, compilation errors occur.
Virtual functions are the way to invoke derived-class-only member functions through the base-class
pointer. Withvirtualfunctions, the type of the object - not the type of the handle used to invoke
the object’s member function - determines which version of avirtualfunction to invoke.
Declare avirtualfunction:
1 v i r t u a l void FunctionName () ;
Choosing the appropriate function to call at execution time (rather than at compile time) is known
as dynamic binding.
When a virtual function is called by referencing a specific object by name and using the dot member-
selection operator (e.g., squareObject.draw()), the function invocation is resolved at compile time
(this is called static binding) and the virtual function that’s called is the one defined for (or inherited
by) the class of that particular object - this is not polymorphic behavior. Dynamic binding with
virtualfunctions occurs only off pointers and references.
To help prevent errors, apply C++11’soverridekeyword to the prototype of every derived-class
function that overrides a base-classvirtualfunction. This enables the compiler to check whether
the base class has avirtualmember function with the same signature.
If a derived-class object with a non-virtual destructor is destroyed by applying thedeleteoperator
to a base-class pointer to the object, the C++ standard specifies that the behavior is undefined.
The simple solution to this problem is to create apublic virtualdestructor in the base class, so
the destructors of any derived classes are alsovirtual.
If a class hasvirtualfunctions, always provide avirtualdestructor, even if one is not required
for the class. This ensures that a custom derived-class destructor (if there is one) will be invoked
when a derived-class object is deleted via a base-class pointer.
Constructors cannot bevirtual. Declaring a constructorvirtualis a compilation error.
In C++11, you can tell the compiler to explicitly generate the default version of a default construc-
tor, copy constructor, move constructor, copy assignment operator, move assignment operator or
destructor by following the special member function’s prototype with = default. This is useful when
you explicitly define a constructor for a class and still want the compiler to generate adefault
constructor as well.
In C++11, a base-class virtual function that’s declared final in its prototype cannot be overridden
in any derived class.
1 v i r t u a l someFunction ( parameters ) f i n a l ;
As of C++11, you can declare a class as final to prevent it from being used as a base class, as in
1 c l a s s MyClass f i n a l { // t h i s c l a s s cannot be a base c l a s s 2 // c l a s s body 3 };
Abstract (base) classes are classes from which you never intend to instantiate any objects. They are
incomplete - derived classes must define the “missing pieces” before objects of these classes can be
instantiated.
A class is made abstract by declaring one or more of itsvirtualfunctions to be “pure”. Apure
virtualfunction is specified by placing “= 0” in its declaration, as in
1 v i r t u a l void someFunction ( parameters ) const = 0; // pure v i r t u a l f u n c t i o n
Pure virtualfunctions do not provide implementations. Each concrete derived class must override
all base-classpure virtualfunctions with concrete implementations of those functions; otherwise,
the derived class is also abstract.
Although we cannot instantiate objects of an abstract base class, we can use the abstract base class
to declare pointers and references that can refer to objects of any concrete classes derived from the
abstract class.
Operatordynamiccastchecks the type of the object to which a pointer points, then determines
whether the type has an is-a relationship with the type to which the pointer is being converted. If
so,dynamiccastreturns the object’s address. If not,dynamiccastreturnsnullptr.
Operatortypeid returns a reference to a typeinfo object that contains information about the
operand’s type, including the type name. It is included in< typeinf o >.