Your browser doesn't support JavaScript cpp Archives - Page 2 of 3 - Windows Programming

The C++ Standard Template Library (STL)

The standard template library (STL) is a set of template classes and functions that supply the programmer with common data structures and functions such as lists, stacks, arrays, sorting etc utilized through templates.

The STL is comprised of the following componentsContainers for storing information
Iterators for accessing the information stored
Algorithms for manipulating the content of the containers

Containers

Containers are STL classes that are used to store data. Each container class defines a set of functions that may be applied to the container. For example, a list container includes functions that insert, delete, and merge elements. A stack includes functions that push and pop values. STL supplies provide the following container classes:Sequential containers
Associative containers
Container Adapters

Sequential Containers

These are ordered collections used to hold data in a sequential fashion. Each element holds a position and that position depends on the time and place of insertion. Adding any objects to the end of a vector means that the object will appear in the order that were inserted. Sequential containers are characterized by a fast insertion time, but are relatively slow in find operations.

The STL provides five sequence container classes:

std::vector – The vector class implements a dynamic array and thus can grow as needed. Although a vector is dynamic, it still uses the standard array subscript notation to access its elements. Compared to the other dynamic sequence containers,vectors are very efficient at accessing elements and relatively efficient adding or removing elements from its end. For operations that involve inserting or removing elements at positions other than the end, they perform worse than the other sequence container classes

std::deque – Similar to std::vector except that it allows for new elements to be inserted or removed at the beginning. Unlike vectors, deques are not guaranteed to store all its elements in contiguous storage locations. Attempting to access and elements by offsetting a pointer to another element will result in undefined behavior. For operations that involve frequent insertion or removals of elements at positions other than the beginning or the end, deques are less efficient than lists and forward lists.

std::list – Are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions. They Operate like a doubly linked list.Compared to other standard sequence containers lists perform generally better in inserting, extracting and moving elements in any position within the container. The main drawback of lists and forward_lists compared to these other sequence containers is that they lack direct access to the elements by their position and thus searching can take extra time. They also consume some extra memory to keep the linking information associated to each element.

std::forward_list – Similar to a std::list except that it is a singly linked list of elements that allows iteration only in one direction. Compared to other base standard sequence containers forward_list perform generally better in inserting, extracting and moving elements in any position within the container. The main drawback of forward_lists is that like the standard list they lack direct access to the elements by their positionand consume extra resources to keep the linking information current.

std::array class – Is a templated class that provides many benefits over built-in arrays, such as maintaining the array size preventing automatic decay into a pointer, providing bounds checking, and allowing the use of C++ container operations.

Associative Containers

Associative containers utilise sorted data structures that can be quickly searched using keys. This results in slower insertion times, but presents significant advantages when it comes to searching.

The associative containers supplied by STL are –std::set 
std::unordered_set
std::map 
std::unordered_map
std::multiset 
std::unordered_multiset
std::multimap
std::unordered_multimap

Container Adapters

Container Adapters offer limited functionality oriented towards a particular container class and providing a more relevant set of functionality. The main adapter classes are:

std::stack — Stores elements in a LIFO (last-in-first-out) fashion, allowing elements to be inserted (pushed) and removed (popped) at the to.

std::queue — Stores elements in FIFO (first-in-first-out) fashion, allowing the first element to be removed in the order they’re inserted.

std::priority_queue — Stores elements in a sorted order, such that the one whose value is evaluated to be the highest is always first in the queue.

Iterators

Iterators are are template classes that act like pointers. They provide the means to cycle and manipulate the contents of a container in much the same way that you would use a pointer to cycle through an array. There are five types of iterators:Bidirectional iterator – Store and retrieve values. Forward and backward moving.
Forward iterator – Store and retrieve values. Forward moving only.
Input iterator – Retrieve, but not store values. Forward moving only.
Output iterator – Store, but not retrieve values. Forward moving only.
Random access iterator – Store and retrieve values. Elements may be accessed randomly.

STL Algorithms

Algorithms act on containers. Each container provides support for its own basic operations however the standard algorithms header provides a more extensive range of functionality. One algorithm function can be used on any type of container. Algorithms from STL are tried and tested saving time & effort when manipulating data. The algorithm library covers sorting, searching,Modifying & Non modifying and Minimum and Maximum operations.

Vector examples

The following code sample uses vectors to create and manipulate an int vector#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector <int> v; // create zero-length vector unsigned int i; cout << "initial size of vector v = " << v.size() << endl;// display original size of v for(i=0; i<20; i++) v.push_back(i); cout << "new size of vector v = " << v.size() << endl; // display new size of vector v cout << "Current contents of vector v:\n"; for(i=0; i<v.size(); i++) cout << v[i] << " ";// display contents of vector v cout << endl; cout << "add 5 elements to vector v:\n"; for(i=0; i<5; i++) v.push_back(i+10);//add 5 more values to vector cout << "new size of vector = " << v.size() << endl;// display current size of v cout << "Current contents of vector v:\n"; for(i=0; i<v.size(); i++) cout << v[i] << " ";// display contents of vector v cout << endl; sort(v.begin(), v.end());//sort contents of vector v cout << "Sort contents of vector v and list\n"; for(i=0; i<v.size(); i++) cout << v[i] << " "; // display contents of sorted vector cout << endl; vector <int> v1(10,5);//create new int vector v1 and initialise elements to 5 cout << "create new int vector v1. Initialise elements to 5. Merge with vector v\n"; for(i=0; i < v1.size();i++)v.push_back(v1[i]);// merged vector v and v1 for(i=0; i < v.size(); i++)cout << v[i] << " ";//display contents of v1cout << endl;cout << "Clear contents of vector v\n"; v.clear();// clear contents of vectorcout << "new size of vector = " << v.size() << endl;return 0;}

The following code sample uses template lists to create and manipulate an int vector#include <iostream> #include <list> using namespace std; int main() { list <int> lst;// create an empty list lst list <int> lst1; // create an empty list lst1 cout << "create random integer lists: " << endl; int rn; for(int a=10;a>0;a=a-1) { lst.push_back(rand()); //add random number to lst lst.push_back(rand()); //add random number to lst1 } list<int>::iterator p = lst.begin();//create pointer p and set to start of lst cout << "output contents of lst: " << endl; while(p != lst.end()) { //iterate through entire lst cout << *p << " "; //output lst value cout << endl; p++; } lst.sort(); cout << "sort lst: " << endl; p = lst.begin(); while(p != lst.end()) { cout << *p << " ";//output lst element cout << endl; p++; } cout << "merge and sort" << endl; lst.merge(lst1);//merge lst and lst lst.sort();//sort lst p = lst.begin(); while(p != lst.end()) { cout << *p << " ";//output lst cout << endl; p++; } }

Templates

A template is a parameterised function for creating a generic class or function. Using templates means one function or class can be used with several different data types, without recoding specific versions for each data type.  A function template starts with the keyword template followed by the template parameter(s) enclosed in angled brackets followed by the function declaration. The general form of a template function definition is −

template <class T>
T someFunction(T arg)
{
}

The generic parameter name can then be substituted for the normal variable type within the preceding function. The compiler will then generate different versions of that function corresponding to the data type within the function call

The following worked example uses a function template to return the maximum of two different values using 3 different value parameter types −

#include <iostream>
#include <string> 
using namespace std; 
//creates template with parameter type myTemplate 
template <typename myTemplate> 
//template function accepts two parameter types a and b 
myTemplate Max (myTemplate a, myTemplate b) 
{ if (a>b) 
{ return a; } 
return b; 
} 
int main () 
{ 
int i = 20; 
int j = 10; 
//calls template function and generates compile time function for int values 
cout << "Max(i, j): " << Max(i, j) << endl; 
double f1 = 13.5; 
double f2 = 20.7; 
//calls template function and generates compile time function for double values 
cout << "Max(f1, f2): " << Max(f1, f2) << endl; 
string s1 = "a"; 
string s2 = "b"; 
//calls template function and generates compile time function for char values 
cout << "Max(s1, s2): " << Max(s1, s2) << endl; 
return 0; 
}

A Function with Multiple Generic Types

A comma-separated list can define more than one generic data type in the template statement. The following worked example accepts two template parameter types and calls the template function using a char and int parameter followed by an int and char parameter.

#include <iostream> 
using namespace std;
//creates template with 2 different parameter types
template <class type1, class type2>
void myfunc(type1 x, type2 y)
{
cout << x << ' ' << y << '\n';
}
int main()
{
//calls template function with parameter types char and int 
myfunc("5x2=", 10); 
//calls template function with parameter types int and char 
myfunc(10, "=9+1"); 
return 0; 
}

Declaring Templates with Default Parameters

Mixing standard parameters with generic type parameters in a template function is possible. In the following worked example a template function, functionX accepts a template parameter and a standard parameter. The standard parameter is set with a default value of 0. The function is first called by specifying only the template parameter type and then called by specifying the template parameter type and standard parameter.

#include <iostream>
using namespace std;
template <typename X> 
//creates template function with template parameter and standard parameter with default value 0
void FunctionX(X value1,int value2=0)
{
if (value2!=NULL)
{
cout << value1 << " ";
cout << value2 ; 
}
else
{
cout << "float value=" << value1 << endl;
}
}
int main()
{
float b=4.33;
// calls template function using only template parameter.
FunctionX(b); 
// calls template function using template parameter and standard parameter.
FunctionX( "float value cast to int =",b);
return 0;
}

To set a default template parameter type in the above code using the following template declaration-

template <typename x=int>

Overloading a Generic Function

Template functions can be overloaded. In the following example, the template function T is overloaded with a function that accepts int parameter values. When the function is called with int values the overloaded function is called. All other parameter values invoke the genetic template function.

#include <iostream>
using namespace std;
template <class X> 
void T(X a, X b)
{
cout << "Inside template T.\n";
cout << a << b;
cout << endl;
}
// This overrides the generic version of t for ints.
void T(int &a, int &b)
{
cout << "Inside overloaded function\n";
cout << a << "X" << b <<"=" << a*b;
}
int main()
{
int i=10, 
j=20;
char *word1="hello ";
char *word2="word ";
T(word1, word2); // calls generic template t()
T(i, j); // calls overloaded function t()
return 0;
}

Variadic functions

Variadic functions can be used to write functions that accept an arbitrary number of arguments. Variable templates or variadic templates have been part of C++ since C++14, released in 2014

#include <iostream>
using namespace std;
template <typename T>
double sum(T t) { //base case
return t;
}
template <typename T,typename... Rest>//recursive case
double sum(T t,Rest... rest) 
{
return t + sum(rest...);
}
int main()
{
double dTotal = 0;
dTotal=sum (33, 3.14, 4.56, 1.1111,44,55);
 cout << "dResult = " << dTotal << endl;
 return 0;
}

The variadic function requires a ‘base’ case and a ‘recursive’ case. In the above example, the compiler finds and executes the sum function for each argument in turn and then executes the base function i.e. the function with no argument. The declaration of a variadic function uses ellipsis as the last parameter. The sizeof…() is an operator that can return the number of template arguments passed in a call to a variable template. In the above code cout<< sizeof…(rest) would return the number of calls left after each iteration. Programmers using variable templates can avoid the repetitive effort of creating code thus making a program shorter and simpler to maintain.

Class Template

It is also possible to write classes that utilise templates. A class template will have members that use template parameters as types. In the example below, the class template is instantiated with an int and a char, and the maximum value is returned.

// class templates
#include <iostream>
using namespace std;
template <class T>
class compare {
T x, y;//declare template class variables
public:
compare (T firstp, T secondp)
{x=firstp; y=secondp;}//set initial value of class variables
T getmax ();
};
template <class T>
T compare<T>::getmax ()
{
T retval;
retval = x>y? x : y;//return highest class variable
return retval;
}
int main () {
compare <int> templateobject (10, 22);//instantiate class template
cout << templateobject.getmax();
compare <char> templateobjectc ('e', 'z');//instantiate class template
cout << templateobjectc.getmax();
return 0;
}

Polymorphism

Polymorphism refers to the ability to access different types of member functions depending on the type of object that invokes the function. Polymorphism can be static or dynamic. In static polymorphism, memory will be allocated at compile time. In dynamic polymorphism, memory will be allocated at run-time.

Compile-Time Polymorphism

This type of polymorphism involved either function or operator overloading

Function overloading

Function or method overloading is the ability to create multiple methods of the same name with different parameter implementations.  In the code section below the first function is called if the parameter is an int, the 2nd function is called if the parameter is a char, and the third if the parameters are two ints.

#include <iostream>
using namespace std; 
class base 
{ 
public: 
    // function with int parameter 
    void func(int x) 
    { 
        cout << "value of x is " << x << endl; 
    } 
    // function with char parameter 
    void func(char x) 
    { 
        std::cout << "value of x is " <<x << " or "<<(int)x << endl; 
    } 
    // function with 2 int parameters 
    void func(int x, int y) 
    { 
        cout << "value of x and y is " << x << ", " << y << endl; 
    } 
}; 
  int main() { 
    base obj1; 
    // Which function is called will depend on the parameters passed 
    obj1.func(33);  // The first 'func' is called  
    obj1.func('!');     // The second 'func' is called 
    obj1.func(33,66); // The third 'func' is called 
    return 0; 
} 

Operator overloading

Operator overloading allows the programmer to define the behaviour of an operator for a particular class. Almost all operators in C++ can be overloaded. To create an overloaded operator, an operator function is created to define the action of the overloaded operator. The function name is preceded by the keyword “operator” and then the symbol for the operator is defined. An overloaded operator function can have a return type and a parameter list.

Generally speaking operators in C++ can be classified into: unary and binary.

Overloading the Binary Addition Operator – the following code segment illustrates how to overload the binary operator by adding two class objects

#include<iostream> 
using namespace std; 
class area { 
private: 
int x,y; 
public: 
area(int a = 0, int b =0)  {x = a;   y = b;} //initialise the object's value 
// overloaded operator '+' 
area operator + (area const &rhs) { 
area returnobject; // Create an object to return 
returnobject.x = x + rhs.x; 
returnobject.y = y + rhs.y; 
return returnobject; 
} 
void print() 
{ 
cout << x << " " << y << endl; 
} 
}; 
int main() 
{ 
area c1(10, 5), c2(2, 4); //declare to area object and initialise
area c3 = c1 + c2; // call to overloaded operator+ 
c3.print(); //output total area
} 

Overloading the unary increase and decrease operator – the following code segment illustrates how to overload the unary increase and decrease Operator

#include  <iostream>
using namespace std;
class Overloaded
{
   private:
      int count;
   public:
       Overloaded(): count(1){}
       void operator ++() //Define overloaded prefix increment operator
       { 
          count = count+1; //increase count by 1
       }
       void operator ++(int) //Define overloaded postfix increment operator
       {
          count = count+10; //increase count by 10
       }
        void operator --() //Define overloaded prefix decrement operator
       {
          count = count -1; //decrease count by 1
       }
          void operator --(int) //Define overloaded postfix decrement operator
       {
          count = count -10; //decrease count by 10
       }
       void DisplayCount () { cout<<"Count: " << count << endl; }
};
int main()
{
    Overloaded value;
    ++value;  //calls prefix increment operator  
    value.DisplayCount();
    value++;  //calls postfix increment operator
    value.DisplayCount();
    --value; //calls prefix decrement operator 
     value.DisplayCount();
    value--;//calls postfix decrement operator 
     value.DisplayCount();
    return 0;
}

Dynamic or Run-Time Polymorphism

In contrast, with compile time polymorphism, the compiler determines which function call to bind to the object after deducing it at runtime. This allows different objects to respond differently to the same method call.

Function Overriding – When a derived class creates a member function with the same return type and signature as a member function in the base class it is said to be overriding that function. Since overriding the base class function will provide a new definition for that function, this allows instances of the derived class to create unique functionality based on the method calls.

In the example code below the base class and derived call are instantiated and the method func is then called from both. To invoke the overridden Methods of a Base Class use the scope resolution operator ( :: )

include<iostream>
using namespace std;
class Base
{
 public:

 void func()
 {
  cout << "Base class function call" << endl;
 }
};
class Derived:public Base
{
 public:
 
  void func()
 {
  cout << "Derived class function call" <<endl;
 }
};
 int main()
{
 Base b;       //Instantiate Base class
  Derived d;   //Instantiate Derived class object
 b.func();     //call func() from base class
 d.func();     //call func() from derived class
 d.Base::func();//call base call func() from derived class
}

Pure Virtual Functions and Abstract Classes

An abstract class is a class that contains at least one pure virtual function. The purpose of an abstract class is to provide a base class that other classes can inherit. Abstract classes cannot be instantiated directly; their purpose is to act as an interface for their subclasses. Attempting to instantiate an object of an abstract class causes a compilation error.  A pure virtual function is declared in the base class, has no body, and is assigned the value 0.

In the example below a pure virtual function is created and implemented in the base class. Without this implementation, the compiler will throw an error –

#include <iostream>
using namespace std;
class Base
{
public:
virtual void pvf() = 0;// pure virtual function
Base(){ //constructor
  cout << "pure virtual constructor called\n"; 
    }
};
// This class inherits from Base and implements method pvf()
class Derived: public Base
{
public:
    Derived(){ //constructor
        cout << "derived constructor called \n";       
    }
void pvf() //implements put virtual function 
{ 
}
};
int main(void)
{
Derived d;
return 0;
}

Characteristics of Abstract Class

  • An abstract class cannot be instantiated, but pointers and references of Abstract class type can be created.
  • An abstract class can have normal methods along with a pure virtual function.
  • Abstract classes are primarily used to provide an interface for any derived class.
  • Classes inheriting an Abstract Class must implement all pure virtual functions, or they will become Abstract too.

Inheritance

Inheritance allows one class to incorporate another class into its declaration. In a situation where two or more classes might have similar attributes, inheritance allows this sharing of common hierarchical functionality. This is usually achieved by creating a base class containing all the common attributes and then allowing the derived class to inherit these shared attributes and define its unique attributes.

When defining a new derived class a colon is placed after the derived class name followed by the level of access ( public, protected, or private ) and then the name of the base class.

In the worked example below a class derived is derived from the base class company. Instantiating the derived class results in the instantiation of the base class –

#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Base Constructer" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived Constructor" << endl;
}
};

int main() {
Derived dobj;
return 0;
}

Public, Protected and Private Inheritance

When one class inherits another, the base class members become members of the derived class. These base class members can only be accessed from within the derived class if the access specifier allows them to be inherited from the base class. The type of inheritance is specified by the access specifier which may be public, protected, or private

  • public – members are accessible from outside the class
  • private – members cannot be accessed (or viewed) from outside the class
  • protected – members cannot be accessed from outside the class, however, they can be accessed in inherited classes. 

Multiple Inheritance

A C++ class can inherit members from more than one class with each base class being separated in the derived class declaration by a comma –

class BaseA { }; class BaseB { }; Class Derived: public BaseA,public BaseB { }

Constructors and Destructors

In C++ more than one constructor will be called when an object of a derived class is created. When any derived class is instantiated the constructor and deconstructor of the base call will also be called.  Base class objects are instantiated before the derived class. Constructors are invoked in order from the top-most (most base-level) class, down to the most derived class. Destructors are invoked in the reverse order. The following example illustrates the order of execution of constructors and destructors in inheritance

#include <iostream>
using namespace std;
class BaseA
{
	public:
		BaseA()
		{
			cout<<"BaseA's Constructor"<<endl;
		}
		~BaseA()
		{
			cout<<"BaseA's Destructor"<<endl;
		}
};
class BaseB : BaseA
{
	public:
		BaseB()
		{
			cout<<"BaseB's Constructor"<<endl;
		}
		~BaseB()
		{
			cout<<"BaseB's Destructor"<<endl;
		}
};
class BaseC : BaseB
{
	public:
		BaseC()
		{
			cout<<"BaseC's Constructor"<<endl;
		}
		~BaseC()
		{
			cout<<"BaseC's Destructor"<<endl;
		}
};
int main()
{
	BaseC c;
	return 0;
}

Passing Parameters during Base Class Initialisation

If a base class contains an overloaded constructor that requires arguments at the time of instantiation then the base class can be initialised by invoking the appropriate base class constructor via the constructor of the derived class-

class Base { public: Base(int value) // overloaded constructor { } }; Class Derived: public Base { public: Derived(): Base(5) // instantiate Base with argument 5 { // derived class constructor code } }

Base Class Pointer to Derived Class Object

C++ Inheritance allows base class pointers to point to derived class objects as both the derived class and base class are pointer type-compatible. 

base *pBase; //declare pointer to type base derived obj; //instantiate derived on obj pBase = &obj;//set pointer to address of obj

In the the code section below a base class pointer pBase points to the derived class object obj. Since pointer pBase cannot access derived class members, then derived class members are not available to the base class pointer. 

#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Base Constructer" << endl;
}
    
void Test()
{
cout << "base class function " << endl;         
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived Constructor" << endl;
}
void  Test()
{
cout << "derived class function " << endl;          
}
};

int main() {
Base* pBase;
Derived obj;
pBase=&obj;
pBase->Test();
return 0;
}

Virtual Functions

A virtual function is a member function declared within a base class and re-defined and overridden by a derived class. When referring to a derived class object using a pointer or a reference to the base class, the derived class function can be called by declaring the function ‘virtual’. When a function is made virtual, C++ determines which function is to be invoked at the runtime based on the type of the object pointed to by the base class pointer and hence is known as dynamic linkage or late binding.  

The code sample below demonstrates both early and late binding –

#include<iostream>
using namespace std;
class Base
{
 public:
void virtual virtfunc()
 {
  cout << "Base Virtual Class" << endl;
 }
   void  func()
 {
  cout << "Base non virtual class" << endl;
 }
};
class Derived:public Base
{
 public:
 void virtfunc()
 {
  cout << "Derived Class" << endl;
 }
  void func()
 {
  cout << "Derived Class non virtual" <<endl;
 }
};
 int main()
{
Base *b;     //Instantiate base class pointer
Derived d;   //instantiate derived class 
b=&d;        //assign derived class object to a base class object
b->func();     // on-virtual function, binded at compile time
b->virtfunc(); // Virtual function, binded at runtime
}

Virtual Destructors

A virtual destructor ensures that when a derived subclass goes out of scope or is deleted the order of destruction of each class is carried out in the correct order. When a pointer to a base class is assigned to a derived class object and that object is deleted, then the base class destructor will be called instead of the derived class destructor. To address this situation, the base class should be defined with a virtual destructor to ensure that the object of the derived class is destructed properly. 

In the worked example below a derived class is instantiated both on the free store and the stack. When the stack object goes out of scope the base destructor is automatically called after the derived deconstructor. To ensure the correct destructor sequence for the base class instantiated using the derived class object it is necessary to include a virtual destructor.  Failure to do so would mean only the base class destructor class being called resulting in memory leak. 

#include <iostream>
using namespace std;
class Base {
public:
    Base() {
        cout << "Base Constructer" << endl;
    }
    virtual ~Base() // virtual destructor
    {
        cout << "Base Destructor" << endl;
    }
};
class Derived : public Base {
public:
    Derived() {
        cout << "Derived Constructor" << endl;
    }
    ~Derived() {
        cout << "Derived Destructor" << endl;
    }
};
void DeleteMemory(Base* pBase) {
    delete pBase;
}
int main() {
    cout << "Allocating a derived object on the free store:" << endl;
    Base* pBase = new Derived;
    cout << "Deleting derived class " << endl;
    DeleteMemory(pBase);
    cout << "Instantiating a derived class on the stack:" << endl;
    Derived drv;
    cout << "Automatic destruction as it goes out of scope: " << endl;
    return 0;
}

Override

The override identifier makes the compiler check the base class(es) to see if there is an equivalent virtual function to that in the derived class. If there is not, the compiler will indicate an error.

class Base { virtual void method(int); }; class Derived : public Base { virtual void method(float) override; // This will produce an error };

Avoiding Inheritance Using final

In C++11 the ability to prevent inheriting from a class or to prevent the overriding of a single method is done with the special identifier final. Any attempts to derive a class from a base class marked as final will result in a compiler error – 

class Base final// no class can be derived from class Base { method(); }; class Base { virtual void method() final;// no class can override method() };

Classes

A class is a user-defined data template consisting of a collection of related variables and functions bundled together as a single entity. The variables can be of any other type, including other classes. Within a class, variables hold the data and the code that operates on the data is contained in functions. Collectively, the functions and variables that constitute a class are called members of the class. A variable declared within a class is called a member variable, and a function declared within a class is called a member function. Grouping these is called encapsulation. Encapsulation makes it possible for other programs to use the class without knowing how it works.

Declaring a Class

A class is defined in C++ using the keyword class followed by the name of the class. The body of the class is defined inside the curly brackets and terminated by a semicolon.

Defining an Object

An object is just an individual instance of a class. When a class is defined, no memory is allocated until it is instantiated. To instantiate the class type the class name followed by the variable name  or place the class name directly after the declaration after the closing bracket

Accessing Class Members

Data members and member functions of a class can be accessed using the dot(‘.’) operator with the object followed by the name of member variables or member functions.

A Simple Class

The code below creates a class box containing 3 public member variables. Since the variables have been declared public, they can be accessed outside the class definition. Two objects of class box are instantiated and each member variable is initialised with a value. The total volume of the box is calculated by multiplying the individual box variables. 

#include <iostream>
using namespace std;
class box //class definition named box
{
public:
int length;//declare public variable length
int height;//declare public variable height
int width;//declare public variable width
} box1;//instantiate class after class declaration (optional)
int main()
 {
box1.height=5,box1.length=30,box1.width=20;//set values of box1 member variables
cout << "Dimensions of box1 are - " << box1.height*box1.length*box1.width;//output box size
box box2;// instantiate class box 2
box2.height=5,box2.length=30,box2.width=20;//set values of box2 member variables
cout << "\nDimensions of box2 are - " << box2.height*box2.length*box2.width;//output box size
return 0;
}

Member Functions

Member functions are operators and functions declared as members of a class. Every class member function that is declared must be defined.  Class functions like other normal functions can have parameters and return a value. There are 2 ways to define a member function:

Outside Class Definition-To define a member function outside the class definition we have to use the scope resolution operator :: along with class name and function name

Inside Class Definition-For those member functions inside the class definition no scope resolution operator is necessary. The function can be defined in the same way as a normal function.

Private, Protected, or Public Members

A class can contain private, protected or public members. By default, all items defined in a class are private.  This means that private members can be accessed only within the functions of the class itself. Public members can be accessed outside the class and protected members are accessible in the class that defines them and in classes that inherit from that class.  Keeping member data private limits access and controls how their values can be changed. Although member variables can be public, it’s considered good programming practice to keep them all private and make them accessible only via the class functions. A function used to set or get the value of a private member variable is called an accessor.

Constructors

Constructors are special class members called every time an object of that class is instantiated. This makes a constructor a perfect place to initialise class member variables. The constructor is a member function with the same name as the class but no return value.  There are 3 types of constructors:

Default Constructors

The default constructor is any constructor that takes no parameters. If not defined by the programmer it is provided by default from the compiler.

Copy Constructors

A copy constructor is a member function which initialises an object using another object of the same class. This will be explained in detail later

Parameterised Constructors

Is a constructor which takes parameters. To create a parameterised constructor, add parameters to it the same way that parameters are initialised in any other function. Using a parameterised constructor enforces the program to supply a necessary variable value as a prerequisite to creating an object.

Constructor with Initialisation Lists – An initialiser list sets class data member’s values. The members to be initialised are listed after the initial parameter declaration and preceded by a colon. Each member variable to be initialised will be listed along with the parameter declaration surrounded by parentheses. This initialisation value can be a parameter or a fixed value.

In the worked example below the box class above is extended to include a constructor to  initialise the member variable: length, height and width

#include <iostream>
using namespace std;
class box //class definition named box
{
public:
int boxsize(); 
box(int,int,int);
private:
int length;//declare public variable length
int height;//declare public variable height
int width;//declare public variable width
}; 
//constructor with optional default values 
box::box(int heightp=10,int lengthp=10,int widthp=10):height(heightp),length(lengthp),width(widthp)
{
height=heightp,length=lengthp,width=widthp; 
}
int box::boxsize()
{
 return height*length*width;
}
int main()
 {
box box1;//create object box1 using default values
cout << "Dimensions of box1 are " << box1.boxsize();//output box1 size
box box2(10,20,30);//create object box2 passing user defined value
cout << "\nDimensions of box2 are " << box2.boxsize();//output box2 size
}

Since the assignment costs using initialiser lists are lower, there is a slight performance advantage over assigning values inside the class body.

Destructors

A Destructor is a member function called automatically when the class object goes out of scope. This happens when:

(1) the function ends or blocks ends
(2) the program ends
(3) the delete operator is called 

Destructors have the same name as the class but are preceded by a tilde (~). Destructors don’t take any argument and don’t return anything. If not defined by the programmer the destructor is provided by default by the compiler.

Friend Functions

A friend function has the right to access all private and protected members of the class but is defined outside the class scope.  The declaration of a friend function should be made inside the body of the class using the keyword friend.

In the code section below the friend function output is used to access the private string name.

#include <iostream>
using namespace std;
class UserDetails
{
private:
string name;
public:
UserDetails(): name("john") { }
//friend function
friend string output(UserDetails);
};
// friend function definition
string output(UserDetails f)
{
//accessing private data from non-member function
return f.name;
}
int main()
{
UserDetails f;
cout<<"Distance: "<< output(f);
return 0;
}

Static Class Members

Static members are class functions not associated with the objects of that class. A static function can access other static members (functions or variables) declared in the same class. A static member can be called using the class name and the scope resolution operator instead of its objects.  Since a static member is created and initialised once, there is only one copy of the static member. This single copy is available to all class objects regardless of how many class objects are created.  Static members do not have access to this pointer of the class.

In the code section below a static member variable is used to keep track of the number of class user objects.

#include <iostream>
 using namespace std;
 class User {
 public:
 static int objectCount;
 // Constructor definition
 User(string n="peter", int a = 32 , string s = "m") {
cout <<"Constructor called." << endl;
name= n;
age = a;
sex = s;
// Increase every time object is created
objectCount++;
}
void userdetails() {
cout << "name-" << name << " age-" << age << " sex-" << sex;
}
static int getCount() {//return objectCount
return objectCount;
}
private:
string name;     
int age;    
string sex;  
} user1;
// Initialise static member of class Box
int User::objectCount = 0;
int main(void) {
//output number of objects
cout << "Object " << User::getCount()<< endl;
user1.userdetails();//output object details
cout << endl;
User user2("mark",32,"m");//create second object
cout << "Object " << User::getCount()<< endl;//output number of object
//output object details
user2.userdetails();
return 0;
}

Const Class Objects and Member Functions

Const Classes – instantiating a const class means that once a const class object has been initialised via a constructor, any attempt to modify the object member variables is disallowed. This includes changing member variables directly or calling member functions that set the value of member variables. Any initialisation is done via class constructors:

Const Member functions – If a member function is declared as constant, it indicates that the function won’t change the value of any class members. To declare a function as constant, put the keyword const after the parentheses –

void function() const;

It is considered good programming practice to use constant functions to avoid accidental changes.

Organising Class and Function Definitions

Class definitions are often kept separate from the source code of C++ programs. Each function declared for a class must have a definition. Like normal functions, the definition of a class function has a header and a body. The definition must be in a file that the compiler can find and will usually be a file with an extension .cpp. Although you can put the declaration in the source code file, most programmers put the declaration in a header file usually ending with the file extension .hpp (or less commonly .h or .hp ).

Anonymous Classes in C++

An Anonymous class is a class declared without an identifier. It is both declared and instantiated at the same time. Since anonymous classes have no identifier there is no way to refer to them beyond the point where they are created and therefore cannot be passed as arguments to functions or be used as return values from functions. Anonymous classes also differ from regular classes in that they have no constructor. The code section below illustrates the declaration of an anonymous class –

#include <iostream>
using namespace std;
class //anonymous class definition 
{
public:
int length;//declare public variable length
int height;//declare public variable height
int width;//declare public variable width
} box1;//instantiate anonymous class 
int main()
 {
box1.height=5,box1.length=30,box1.width=20;//set values of box1 member variables
cout << "Dimensions of box1 are " << box1.height*box1.length*box1.width;//output box size
return 0;
}

Smart Pointers

A smart pointer is a C++ class that encapsulates or wraps a standard C++ pointer. With raw pointers, the programmer has to explicitly destroy the object when it is no longer needed; smart pointers ensure the correct destruction of dynamically allocated data memory. 

C++11 introduced three types of smart pointers, all of them defined in the <memory> header found in the Standard Library:

unique_ptr

The unique_ptr<> is a scoped pointer that is automatically deleted when the object is destroyed, or as soon as its value is changed, either by using the assignment operation or by an explicit call to unique_ptr::reset.  A unique pointer cannot be copied.

The following code section generates 3 unique smart pointers and initialises them. When the function goes out of scope the memory allocated to the pointers is freed.

#include <iostream>
#include <string.h>
#include <memory>
using namespace std;
void smartptr()
{
//smart pointer to int
std::shared_ptr <int> intPtr(new int );  
//smart pointer to int array
std::shared_ptr <int> intarrayPtr(new int[100], std::default_delete<int[]>() );
// smart pointer to char array
std::shared_ptr <char> chararrayPtr(new char[100], std::default_delete<char[]>());
*intPtr=100;//set int value
intarrayPtr.get()[5]=5;//set int array value
strcpy(chararrayPtr.get(),"smart array");//set int char value
cout << "intPtr value: " << *intPtr<< endl;//out int value
cout << "intarrayPtr value: " << *(intarrayPtr.get()+5)<< endl;//out int array value
cout << "chararrayPtr value: " << (chararrayPtr.get())<< endl;//output int char value
}
int main()
{
smartptr();
//any attmempt to access the smart pointer values out of scope will fail
return 0;
}

shared_ptr

The shared_pointer is a smart pointer that can store and pass a reference beyond the scope of a function. shared_ptr instances share the ownership of the data which is only destroyed when all instances of the shared_ptr are removed. Reference Counting is a technique for storing the number of references to a particular resource.

#include <memory>
#include <iostream>
std::shared_ptr<int> func()
{
 std::shared_ptr<int> valuePtr(new int(15));
 return valuePtr; // no memory leak when smart pointer goes out of scope
}
 int main()
{
 std::shared_ptr <int> valuePtr1=func();
 std::cout << *valuePtr1;
}

weak_ptr

A weak_ptr is created as a copy of shared_ptr. It provides access to an object but does not participate in reference counting and does not affect the shared_ptr or its other copies. Users can check the validity of the data by calling expired() or lock() functions. 

#include <memory>
#include <iostream>
int main()
{
 std::shared_ptr<int> sPtr(new int(15));//create and initiate shared smart pointer
 std::cout << "shared pointer value is " << *sPtr << "\n";
 std::weak_ptr <int> wPtr = sPtr;//set weak pointer to shared pointer
 *sPtr = 10;//change value of shared pointer
 std::cout << "weak pointer value is " << *wPtr.lock()<< "\n";//weak pointer does not change
 sPtr.reset();//delete shared pointer
 if (wPtr.expired())//check if weak pointer exists
 {
 std::cout << "weak pointer value has been deleted";
 }
}

In addition to the above, the C++ library includes the smaerstd::auto_ptr. This is now deprecated.

C++ Memory Map and Free Store

The memory that a program uses is typically divided into a few different areas:

• Global namespace – contains global variables
• The free store (heap) – contains dynamically allocated variables 
• Registers – are used for internal housekeeping functions, such as keeping track of the stack and the instruction pointer.
• Code space – contains the program.
• The stack – used for storing function parameters, local variables, and other function-related information are stored.

The free store

Free Store is a large pool of unallocated memory used by the program for dynamic memory allocation during the execution of the program.  Objects allocated on the free store are manipulated indirectly through pointers. Free store memory is allocated through the use of the new operator and deallocated through the delete operator.  The advantage of the free store is that reserved memory is available until its explicitly released. If memory is allocated on the free store while in a function, the memory will still available when the function returns.  The disadvantage of the free store is that that reserved memory remains unavailable until its explicitly released. Failure to free this memory can build up over time resulting in memory leak which can result in performance issues and a possible system crash. 

Allocating Space with the new Keyword

Memory is allocated on the free store by using the new keyword followed by the type of the object that is to be created. This tells the compiler how much memory to set aside.  To request new memory for a variable type int using the following –

int *ptr = NULL; – creates a pointer ptr and assigns NULL
ptr = new int; – allocated space for an int on the heap and assign is address to pointer ptr

or

int *p = new int

Deallocating Space with the delete Keyword

When an area of free store is no longer required, its must freed back to the system because memory allocated with new is not freed automatically. This is done by calling delete on the pointer.  If a pointer variable is pointing to free store memory and the pointer goes out of scope, the memory is not automatically returned to the free store and becomes unavailable. This is called a memory leak. To release memory back to the free store use the keyword delete – 

delete pPointer;

The code section below illustrates the allocating and deleting of a pointer

#include <iostream>
using namespace std;
int main()
{
int * pInt= new int;//create pointer pInt
*pInt=7;//assign value 7
cout << "*pInt: " << *pInt << endl;//output value of pInt
delete pInt;//delete pointer
cout << "*pInt after deleting: " << *pInt << endl;//output pointer value
return 0;
}

If there is insufficient space on the heap the request to allocate memory will fail. The new request will be in the form of an exception of type std::bad_alloc.  If “nothrow” is used with the new operator, it will return a NULL pointer. To add a free store request fail exception to the above code segment –

int *pInt = new(nothrow) int;
if (!pInt)
cout << "allocation of memory failed\n";

Functions

A function is a unit of code grouped to perform a specific task. Functions provide a way to compartmentalise and organise a program. Functions are identified by a name, enclosed within scope brackets, and may be terminated by a return statement. After a function call, the execution of the program branches to the first statement in that function and continues until it reaches a return statement or the function’s last statement. At that point, execution resumes at the place where the function was called. A function can have multiple parameters separated by commas, but it can have only one return type. A function that does not need to return a value is declared void.  In C++, one function cannot be embedded within another function. Functions are denoted by the function name followed by the parentheses and preceded by the return type(if any).

Function Prototype

The function prototype declares a function before its definition and details its name, the list of parameters the function accepts, and the return type. The compiler needs to know this information before the function is called. A function defined before main() (forward declaration) does not need a function prototype.

Function calls

A function call is an expression that passes control and arguments (if any) to a function. When a function declaration contains parameters, the function call sends arguments. Arguments are values the function requests within its parameter list.

Function Parameters

The purpose of parameters is to allow functions to receive arguments. These parameters don’t have to be of the same data type. Any valid C++ expression can be a function parameter, including constants, logical expressions, objects, and other functions that return a value. Parameter data can be passed into and out of methods and functions by value or reference with multiple parameters separated by a comma.

Pass by Value – The data associated with the actual parameter is copied into a separate storage location assigned to the function parameter. Any modifications to the function parameter variable inside the called function or method affect only the local parameter.  The parameters passed to a function become local variables within that function, even if they have the same name as variables within the scope of the statement calling the function.

Pass by Reference – Using “pass by reference”, the function parameter receives a reference or pointer to the variable in the calling environment. Any changes to the function parameter are reflected in the original calling environment variable.

Pass-by-references are more efficient than pass-by-value because it does not copy the arguments.

The code selection below outlines 3 different methods for passing data to a function

#include <iostream> 
using namespace std;
void swapThemByVal(int, int);
void swapThemByRef(int& , int&);
void swapThemByPtr(int *, int *) ;
main() 
{
int x = 10, y = 20;//declare and initialise variable values
swapThemByVal(x, y);//pass be value
cout << x<< "  " << y << endl;     // displays 10  20
swapThemByRef(x, y);//pass by reference
cout << x << "  " << y << endl;     // displays 20  10
swapThemByPtr(&x, &y);//pass by pointer
cout << x << "  " << y << endl;     // displays 10  20
return 0; 
}
void swapThemByVal(int num1, int num2) 
{
int temp = num1;
num1 = num2;
num2 = temp;
}
void swapThemByRef(int &num1, int &num2) 
{
int temp = num1;
num1 = num2;
num2 = temp;
}
void swapThemByPtr(int *num1, int *num2) 
{
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}

Default Function Parameters

Normally when a function is declared in a prototype to receive one or more parameters, the function can only be called with parameters of that data type, however, if the function prototype declares a default value for a parameter the function can be called without that parameter.

Default arguments are only allowed in the parameter lists of function declarations. The default values can be overridden with a user-supplied value if required using the normal call syntax. When a function has more than one parameter, default values are assigned based on the order of the parameters. Any parameter can be assigned a default value, with one important restriction: If a parameter does not have a default value, no previous parameter may have a default value.

The following declaration is not permitted

long setvalues(int x, int y, int z = 1, int t) – note that x & y are before z

The correct declaration would be

long setvalues(int x, int y, int t,int z = 1);

Passing an Array of Values to a Function

C++ does not allow an entire array to be passed as an argument to a function. Pointers to an array are passed as an argument by specifying the array’s name without an index. The argument represents the memory address of the first element of the array. Any changes in the function will therefore be reflected in the original array. To pass a single-dimension array as an argument in a function using one of the following.

All these variants are functionally identical. Each effectively tells the compiler that an integer pointer is to be received.

void myFunction(int *param) - array passed as pointer void myFunction(int param[10])  - array passed a sized array void myFunction(int param[]) - array passed as unsized array

Returning Values from Functions

Functions can return a value or return nothing (void).To return a value from a function, the keyword return is followed by the value to return. A function’s return value is copied into a placeholder on the stack. The return value is popped off the stack and can be assigned as the value of the function. If the value of the function isn’t assigned to anything, no assignment takes place, and the value is lost. After a return statement, program execution continues immediately after the statement that called the function. A function can have multiple return statements

Auto-Typed Return Values

Another feature added with version C++14 is the automatic deduction of a function’s return type with the auto keyword. This tells the compiler to deduce the return type of the functions by deduction –

auto subtract(int x, int y) { return x — y; }

Functions that rely on automatic return type deduction need to be defined before invoked so the compiler knows a function’s return type where it is used. If a function has multiple return statements, they need to be the same type.

Using Variables with Functions

Local Variables – A variable created in a function is called a local variable because it only exists within the function scope. When the function returns, all local variables go out of scope and cease to exist. Local variables are declared like any other variable. The parameters received by the function are also considered local variables. Local variables get stored in an area of memory called the stack.

Global Variables – In C++, variables defined outside of all functions, including the main() function are known as global variables and are visible everywhere in the program.  Since Global variables can be changed in any part of the program this can lead to a problem in tracking down errors.  Limiting the scope of a variable to a particular section of a program limits the amount of checking that must be done in the event of an error. The use of global variables is not considered good programming practice. Non-constant global variables are stored in the “data” segment of memory

Overloading Functions

Functions with the same name and return type but with different parameters are called overloaded functions. Overloaded functions can be used in situations where the function called depends on the type of parameters specified in the function call. It is, therefore, possible to create a function that performs a task on different data types without creating unique names for each function. For example – 

int proc(int); int proc(int, int); int proc(long, long); int proc(cint);

The proc function above is overloaded with four different parameter lists. The second and third differ in the data types and the third and fourth differ in the number of parameters. The parameters the function is called with determine which function will be called. Overloaded functions don’t have to have the same return type, but it is not possible to overload by return type.  Function overloading is also called function polymorphism.

Inline Functions

Since a function call results in some overhead, declaring a function as inline causes the contents of the function to be placed inline where it’s called.  The C++ compiler carries out this substitution at compile time. Inline functions will generally only increase efficiency if they are small. To make any function inline, start its definitions with the keyword “inline”.

The syntax for defining the function inline is:

inline return-type function-name(parameters) { // code }

Recursion—Functions That Invoke Themselves

A function that calls itself is known as a recursive function. The recursion proceeds until some condition is met which breaks the recursive cycle. The following simple recursion function demonstrates how a countdown procedure calls itself until the exit condition is met.

#include <iostream>
void printFun(int countp) 
{ 
if (countp < 1) //exit function if value of countp is smaller than 1
return; 
else
{ 
printf("Count value = %.i \n", countp);
printFun(countp-1); //recursive function calls itself
return; 
} 
} 
int main() 
{ 
int count = 3; 
printFun(count); //call recursive function
}

Controlling Program Flow

Conditional Execution

Conditional execution of code is implemented in C++ using the if … else or Select..case construct.  Multiple lines of code can be enclosed within statement blocks.

The if Statement: The if statement selects and executes statement(s) based on a predefined condition. The statement(s) are only executed if the condition evaluates to true. If the condition evaluates to false, execution is skipped and the program control passes to the statement following the if statement.

The syntax of the if statement is

if (condition) { statement 1; statement 2; }

The if-else Statement: The if-else statement causes one of the two possible statement(s) to execute, depending upon the outcome of the predefined condition.

The syntax of the if…else statement is

if (condition) {// code block if condition is true Statement 1; Statement 2; } else {// code block if condition is not true Statement 3; Statement 4; }

Nested if-else – contains one or more if-else statements and is validated against several different conditions, which themselves may be dependent on the evaluation of a previous condition

if( expression1 ) // code block if expression 1 is true statement1; else if( expression2 ) // code block if expression 2 is true and expression 1 is false statement2; else // code block if previous conditions are all false statement3;

If expression1 is evaluated to true, statement1 is executed before the program continues. If the expression1 is not true, expression2 is checked and if it evaluates to true, statement2 is executed. If both expression1 and expression2 are false, statement3 is executed. Only one of the three statements is executed.

Conditional Processing Using Switch-Case

The switch-case conditional statement enables a check on a particular expression against a host of possible constant conditions and performs a different action for each of those different values. Each case statement ends with a break statement that causes execution to exit the code block.

The following is the syntax of a switch-case construct:

switch(expression) { case optionA: DoSomething; break; case optionB: DoSomethingElse; break; default: CatchAllWhenExpressionIsNotHandledAbove; break; }

In most situations, a break ends each section however in some situations it may be necessary to execute multiple case statements. If a break statement does not end the statement sequence associated with a case, then all the statements at and below the matching case will be executed

The Conditional Operator ‘? :

The conditional operator is similar to an if-else statement and selects one of the two values or expressions based on a given condition. It cannot select or execute more than one value at a time.

in the example below the variable highvalue is set to the greater of two given numbers contained in variable num1 and variable num2

int highvalue = (num1 > num2)? num1 : num2;

Looping

Many tasks in a program are accomplished by carrying out a repetitive series of instructions, a fixed number of times or until a specific condition is met. A block of such code is called a loop. Each pass through the loop is called an iteration and the code blocks are called compound statements.

While Loops

A while loop causes a code block to be executed repeatedly as long as a starting condition remains true. The while keyword is followed by an expression in parentheses. If the expression is true, the statements inside the loop block are executed until the expression is false. If the initial condition is not met code inside the block is not executed. In the following code sample, the while loop counts to 10 and exits the loop when the variable i is equal to 10

#include <iostream> 
int main() 
{
int i;
while (i <=10) //test condition
{
std::cout << ++i << "\n";//output value of i
}
}

Do-While Loops

A do-while loop is a control flow statement that executes a code block at least once. In contrast to a while loop which starts with a conditional expression before code execution, the do-while loop checks the condition after the block is executed. In the following example, the loop’s conditional statement is only true when i < 5. Since i begins with a value of 10, this condition is never true however the body of the loop executes once.

#include <iostream> 
int main() 
{
int i = 10;
do
{
std::cout << ++i << "\n";//output value of i
} while (i < 5);//test condition
}

For Loops

Is an iterative control flow statement that allows code to be executed a specific number of times. The exit condition is checked at the beginning of every loop, and the variable value at the end. The syntax of a for loop is –

for ( init; condition; increment ) { statement(s); }

The optional init step is executed first, and only once, and allows the programmer to declare and initialise any loop control variables. If no initialisation is specified a semicolon must be used.

Following initialisation, the condition is evaluated. If it is true, the body of the loop is executed. If it is false, the loop body does not execute and the control flow jumps to the next statement just after the for loop.

After the body of the for loop executes, the control control jumps back up to the increment statement. This process is repeated until the condition becomes false, after which the loop terminates.

Leaving any parameter blank in a for-next declaration means the condition will start with a null value. You can create an infinite loop by using for(;;)

In the code section below, a for loop is declared, and the variable i is initialised to 0. The value of value i is then checked and if the exit condition (i<10) is not met the body is executed. The variable i is then incremented at the end of the loop and the process is repeated until the condition statement returns false and the loop exits.

#include <iostream> 
int main() 
{
for (int i = 0; i < 10; i++)//initialise loop 
{
std::cout << i;//output value of i to screen
}
}

Advanced for Loops – It is possible to create multiple loops within one statement by placing the initialisation and action sections in one statement separated by commas.

In the example below this loop has two variable initialisations: a and b, each separated by a comma. The loop’s test section tests whether a < 10 and both integer variables are incremented.

for (int a = 0, b = 0; a < 10; a++, b++)

Nested Loops – Loops can be nested with one loop sitting in the body of another. The inner loop will be executed in its entirety for every execution of the outer loop. C++ allows at least 256 levels of nesting –

for ( init; condition; increment ) { for ( init; condition; increment ) { statement(s); } statement(s); // you can put more statements. }

The Range-Based For Loop –  Introduced in C++11 the range-based loop executes on a predefined range of values such as those contained in an array

For example, given an array of integers, you would use a range-based for loop to read elements contained in the array –

#include <iostream> 
int main() 
{
int myvalues[] = { 1, 88, 33, -5,13};
for (int aNum : myvalues) // range based for
{
std::cout << "The array elements are " << aNum <<"\n";
}
}

Continue and Breaking

The break statement causes a loop to end immediately, instead of waiting for its condition to be false. When the break statement is encountered inside a loop, the loop is immediately terminated and program control resumes at the next statement following the loop

Continue resumes execution from the top of the loop. The code following it within the block is skipped. Thus, the effect of continue in a while , do...while , or for loop is that it forces the next iteration of the loop to take place, skipping any code in between.

#include <iostream>
using namespace std;
int main () 
{
int a = 10;
do { 
a=a+1; 
if( a == 15) //check if a=15. skip to end of loop
{
continue;    
}   
cout << "value of a: " << a << endl;
} while( a < 20 );
return 0;
}

Usually, programmers expect all code in a loop to be executed when the loop conditions are satisfied. Continue and break modify this behaviour and can result in non-intuitive code. Therefore, continue and break should be used sparingly

The Goto Statement

Goto performs a one-way transfer of control to another point in the program. This requires an unconditional jump ignoring any existing program flow such as nesting and does not cause any automatic stack adjusting. The destination point is identified by a label, which is then used as an argument for the goto statement. A label is a valid identifier followed by a colon (:). It's advised to use goto statements with caution and preferably not at all since their misuse can lead to an unpredictable flow of code, difficult-to-read programming(spaghetti code), and in some cases unpredictable variable states.

The syntax for the goto statement is

{
Start: // Called a label
UserCode;
goto Start;
}

Exiting the Program

Under normal circumstances, a C++ program terminates when execution reaches the closing brace of the main() function.

Program termination can, however, be initiated by the program by calling the library function exit() abort ad atexit. To use these functions, a program must include the header file <cstdlib>

Exit Function

The exit function terminates a C++ program and the argument value supplied to the exit function is returned to the operating system as a return code. A return code of zero means the program was completed successfully and a value of 1 indicates that the program terminated with an error. The syntax of this function is

void exit ( int status );

In addition, the header file also defines two constants for use as arguments to the exit() function:

define EXIT_SUCCESS define EXIT_FAILURE

Abort Function

The abort function terminates the program immediately bypassing the usual run-time termination processing. The syntax for the abort function is

void abort ();

Atexit Function

The atexit function is used to specify actions that execute before the program terminates. The syntax for the atexit function is

int atexit (void (*func)(void));

The following short program demonstrates how to call a function before closing the program

#include <iostream>
#include <cstdlib>
using namespace std;
void closing()
{
	cout << "Program closure successful";
}
int main()
{
	int x;
	x = atexit(closing);
	if (x != 0)
	{
	cout << "Program Failure";
	exit(1);
	}	
cout << "Program successful" << endl;
return 0;
}

Expressions Statements and Operators

All C++ programs are made up of statements, which are commands that are executed one after another. All statements in C++ end with a semicolon. Each statement takes up one line by convention, but this is not a requirement. Multiple statements can be put on a line as long as each ends with a semicolon. 

To spread a statement over two or more lines, you can do it by adding a backslash ( \ ) to the end of the line

cout << "Hello \ World" << endl; // split to two lines is OK

Whitespace

Whitespace is a term that refers to characters that are used for formatting purposes. In C++, this refers primarily to spaces, tabs, and (sometimes) newlines. The C++ compiler generally ignores whitespace, with a few minor exceptions. Whitespace serves the purpose of making the code more readable to programmers.

Compound Statements

A compound statement is one or more statements enclosed within a bracket{}.

Although every statement in a compound statement must end with a semicolon, the compound statement itself does not end with a semicolon. Variables declared within the statement are local to that compound statement.

Operators

An operator is a symbol that tells the compiler to perform a specific mathematical or logical operation.

Arithmetic Operators

assuming a=2 and b=1

Operator Description Example
+ Adds two operands A + B will give 3
Subtracts the second operand from the first A – B will give 1
* Multiplies both operands A * B will give 2
/ Divides numerator by de-numerator A / B will give 2
% Modulus Operator and the remainder of after an integer division A % B will give 0
++ increases operator value by one A++ will give 3
decreases operator value by one A– will give 1

Postfix or Prefix?

In C++ the increment ++ operator increases the value of a variable by 1 and the use of the decrement — operator decreases the value of a variable by 1 however, where the operator is placed has an important effect on how operations are evaluated.

Placing the operator before the operand ie ++var causes the variable value to be increased it returns a value.

Placing the operator after the operand ie var++ causes the variable value to be returned before var is increased.

Relational Operators

assuming a=2 and b=1

Operator Description Example
== returns true (1) if two operands have the same value otherwise returns false (0) (A == B) is not true.
!= returns true (1) if two operands don’t have the same value otherwise returns false (0) (A != B) is true.
> returns true (1) if the left operand is greater than the value of the right operand otherwise returns false (0) (A > B) is true.
< returns true (1) if the left operand is less than the value of the right operand otherwise returns false (0) (A < B) is false.
>= returns true (1) if the left operand is greater than or equal to the value of the right operand otherwise returns false (0) (A >= B) is true.
<= returns true (1) if the left operand is less than or equal to the value of the right operand otherwise returns false (0) (A <= B) is false.

Logical Operators

Assume variable A holds 2 and variable B holds 1, then −

Operator Description Example
&& the logical AND operator evaluates two expressions.If both expressions are true, the logical AND expression is true. A==2 && B==1 result is TRUE
|| The logical OR operator evaluates two expressions. If either is true, the expression is true A==2 || B==1 result is TRUE
! A logical NOT statement reverses a normal expression, returning true if the expression is false and false if the expression is true. !(A==2) result is FALSE

Bitwise Operators

The bitwise operator works on bits and performs bit-by-bit operations. the difference between logical and bitwise operators is that bitwise operators don’t return a boolean result but manipulate individual bits.

The Bitwise operators supported by the C++ language are listed in the following table. Assume variable A holds 50 and variable B holds 25, then −

A = 0011 0010

B = 000 11001

Operator Description Example
& Binary AND Operator copies a bit to the result if it exists in both operands. (A & B) will give 16 which is 0001 0000
| Binary OR Operator copies a bit if it exists in either operand. (A | B) will give 59 which is 0011 1011
^ Binary XOR Operator copies the bit if it is set in one operand but not both. “>(A ^ B) will give 43 which is 00010 1011
~ is a unary operator and has the effect of ‘flipping’ the bits. (~A ) will give -51 which is 1111111111001101 in 2’s complement form.
<< Binary Left Shift Operator. The left operand value is moved left by the number of bits specified by the right operand. A << 1 will give 100 which is 0110 0100
>> Binary Right Shift Operator. The left operand value is moved right by the number of bits specified by the right operand. A >> 2 will give 12 which is 0000 1100

Assignment Operators

Operator Description Example
= Assigns values from right-side operands to left-side operands. C = A + B will assign the value of A + B to C
+= add the value of the expression to the value of the variable to the left of the operator, and assign the result to that variable C += A is equivalent to C = C + A
-= subtract the value of the expression from the value of the variable to the left of the operator, and assign the result to that variable C -= A is equivalent to C = C – A
*= Multiply the right operand with the left operand and assign the result to the left operand. C *= A is equivalent to C = C * A
/= Divide the left operand with the right operand and assign the result to the left operand. C /= A is equivalent to C = C / A
%= Take modulus using two operands and assign the result to the left operand. C %= A is equivalent to C = C % A
<<= Left shift AND assignment operator. C <<= 2 is same as C = C << 2
>>= Right shift AND assignment operator. C >>= 2 is same as C = C >> 2
&= Bitwise AND assignment operator. C &= 2 is same as C = C & 2
^= Bitwise exclusive OR and assignment operator. C ^= 2 is same as C = C ^ 2
|= Bitwise inclusive OR and assignment operator. C |= 2 is same as C = C | 2

Misc Operators

?—-known as a ternary operator because it requires three operands. Can be used to replace if-else statements

example:y = (x > 10) ? 10 : 20;

Here, y is assigned the value of 10 if x is greater than 10 and 20 if not

. ->(dot and arrow)—- used to reference individual members of classes, structures, and unions.

&(ampersand) —- returns the address of a variable. For example &x; returns location of the variable x in memory

*(asterisk)—- Used to Declare and Dereference a pointer

,(Comma operator)—causes a sequence of operations to be performed. The value of the entire comma expression is the value of the last expression of the comma-separated list. The value of a comma-separated list of expressions is the value of the right-most expression This means that the expression on the right side will become the value of the entire comma-separated expression

example: var = (value1 = 1, value2 = 2, Value1+1);

This statement first assigns the 1 to value1, assigns the 2 to value 2, increments value1 by 1 and finally, assigns the value of value1 to var. The parentheses are necessary because the comma operator has lower precedence than the assignment operator.

Operator’s Precedence in C++

The order in which operators are evaluated in a compound expression is called operator precedence.  In C++, when the compiler encounters an expression, it must analyze the expression and determine how it should be evaluated. To assist with this, all operators are assigned a level of precedence. Those with the highest precedence are evaluated first.

Here, operators with the highest precedence appear at the top of the table, and those with the lowest appear at the bottom. Within an expression, higher precedence operators will be evaluated first.

for example

int myNumber = 20 * 50 + 25 – 25 * 25 << 2;

simplifies to 1000+25-625>>2

simplifies to 400>>2=100

Rank Name Operator
1 Scope resolution ::
2 Member selection, subscription, increment, and decrement . ->
2 Member selection, subscription, increment, and decrement. . ->()++ —
3 sizeof, prefix increment and decrement, complement, and, not, unary minus and plus, address-of and dereference, new, new[], delete, delete[], casting, sizeof() ++ –^ !- +& *()
4 Member selection for a pointer. .* ->*
5 Multiply, divide, modulo * / %
6 Add, subtract + –
7 Shift (shift left, shift right) << = >>=
8 Inequality relational == !=
9 Equality, inequality == !=
10 Bitwise AND &
11 Bitwise exclusive OR ^
12 Bitwise OR |Rank Name Operator |
13 Logical AND && &&
14 Logical OR ||
15 Conditional ?:
16 Assignment operators = *= /= %= += -= <<= >>= &= |= ^=
17 comma ,