OOP with C++ :

Namespaces

using namespace std; // what does this imply ? what is a namespace ? what is its use ?
  • A namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it. Namespaces are used to organise code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.

  • The statement above simply says that we are using software components from the C++ standard library, such as when you are using cout, it is actually std::cout .

Inline Functions

Some functions are of quite small size, but quite frequently called. C++ provides an inline functions to reduce the function call overhead. Inline function is a function that is expanded in line when it is called. When the inline function is called whole code of the inline function gets inserted or substituted at the point of inline function call. This substitution is performed by the C++ compiler at compile time . Inline function may increase efficiency if it is small. Know more here

For a function to be inline, it can't contain a loop, static variables, switch or goto statement. Also, an inline function should not be recursive and if its return type is other than void then, return statement should be present in function body. If the function definition of a member function of a class is written inside the class itself, then that function is implicitly inline.

Advantages of inline function

  • It also saves the overhead of push/pop variables on the stack when function is called.
  • It also saves overhead of a return call from a function

Reference variables

It is nothing but a different name (alias) for the same memory location . Eg.

int a=33;
int &b= a; /* Here, b is a reference for variable a DON'T CONFUSE THIS WITH POINTERS*/
cout << b; // output :- 33

Call by reference [ 2 methods ]

(A) Using pointers (similar to C) - Actually call by address Eg.

void swap (int * a, int * b)
{
int t;
t=*a;
*a=*b;
*b=t;
}

In main(), we pass the addresses of variables to swap, swap(&c,&d);

(B) Using reference variables A reference is declared by putting "&" in front of the identifier in the function header . A reference is not a variable. It is just an alias of a variable. Eg.

void swap (int & a, int & b)
{
int t;
t=a;
a=b;
b=t;
}

In main(), just call normally, swap(c,d); (It will automatically pass by reference)

Default arguments to functions-

However, only the rightmost arguments can be omitted i.e. you can not provide the 1st and 3rd argument and omit the middle one

Eg.

 float si (float principal,  int r, int t=1 )
{
return t*r*principal;
}

In main(), call as si(33.00,2); It returns 66.00 taking default value of t as 1 because only 2 arguements are passed.

Polymorphism

  • Polymorphism is a feature of OOPs that allows an object to behave differently in different conditions.

Types of polymorphism

types

Binding

  • For function calls, binding means matching the call with the right function definition by the compiler. It takes place either at compile time or at runtime.

  • There are 2 types of binding :

    i. Early Binding or static binding (Compile-time time polymorphism)

    ii. Late Binding or dynamic binding (Run time polymorphism)

Function Overloading

  • Functions with the same name but different signature (i.e. argument list or parameter list) are called overloaded functions. Overloaded functions are recognised by the compiler through the argument list in the call.

  • Example

void area(int a);  // for calculating area of circle
void area(int a, int b); // for calculating area of rectangle using the same function

Function pointer and call-back technique

Just like an array name is the address of the first array element, a function name is a actually the starting address of the function code. For more, view here. Eg.

void fun(int a) 
{ 
    printf("Value of a is %d\n", a); 
} 

int main() 
{ 
    // fun_ptr is a pointer to function fun()  
    void (*fun_ptr)(int) = &fun;   // Note the brackets 

    /* The above line is equivalent of following two 
       void (*fun_ptr)(int); 
       fun_ptr = &fun;  
    */

    // Invoking fun() using fun_ptr 
    (*fun_ptr)(10); 

    return 0; 
} 

Array of pointers to a function:-

(Only Useful in a menu-driven system, when all Functions have same signatures and prototypes)

 char (*funPtr[3])(int) = {fun1, fun2,fun3}; 
 int choice = 0; 

 while(choice != -1) 
 { 
 (*funPtr[choice])(); 
 cin >> choice; 
 }

Classes in C++:-

  • Class : It is a user-defined data type, which holds its own data members and member functions, which can be accessed and used by creating an instance of that class. Class acts as a blueprint for an object.

  • Object : An instance of a class, that has some properties (data members) and behaviours (member functions) associated with it.

  • When a class is defined, no memory is allocated but when it is instantiated (i.e. an object is created) memory is allocated.

  • There are 3 member access specifiers- public, private, protected All data members and methods declared by the public specifier are accessible from outside, and all declared by private are only accessible for methods.

  • If the method is defined inside the class body, it is automatically inlined. It may improve the performance (As it avoids calling of function) , but it is not good for information hiding, because the client of the object is able to see the implementation of its methods.

  • To define the method outside the class body , you have to use scope resolution operator ::

  • Private and protected data members can also be changed by friends of its class.

  • Both structures and classes have private, public and protected access specifiers. Default access specifier of classes is private, default for structure is public.

  • There are basically 5 types of member functions :-

  1. Constructor (create an object with a legal initial value)

  2. Access methods (getters and setters)

  3. Service Methods (for services)

  4. Utility Methods (private methods, which are called only by other methods of the same class)

  5. Destructor (Destroying or releasing memory occupied by an object)

Constructor and Destructor :-

Constructors

(A) There is a special method with the same name as the class called constructor . There is no return type (even not void) for this special method. Constructors can be overloaded .

(B) 3 types of constructor:-

  1. Default - No arguement Used mostly for creating an array of objects

  2. Parameterized - has some arguements

  3. Copy Constructor - has an argument its own type, to copy a new object out of it.

  • It uses Call by reference, Otherwise the copy constructor call results in infinite recursion , because for call-by-value, a copy of the object passed to the copy constructor must be made, which results in the copy constructor being called recursively

  • Also, The object argument passed to the copy constructor must be constant. Otherwise it can not be applied on constant object. For more, view here

(C) When the user defines a parametrized Constructor, it hides the default constructor.

(D) If you want to have an array of objects that do not have a default constructor , the work-around is to have an array of pointers and initialize them using operator new . See examples here

(E) If copy constructor is not provided, compiler will provide a default copy constructor , which makes default memberwise copy, which can not deal with objects with pointer members (it will perform only shallow copy of pointers) . As in C++, objects are passed by value, by default , a copy constructor is generally required.

  • Note : This is different from JAVA where all objects are passed by reference and the language even does not support automatic pass-by-value, there is no need for enforcement of copy constructors. For the purpose of cloning objects, Java provides a more robust and automated facility – the clone mechanism.

Destructors

(A) Automatically called when an object leave scope to release all resources held by the object. The name of a destructor for a class is the tilde (~) character followed by the class name. Stack memory resources held by the object such as its compiler-created members are released automatically when the object leaves scope or explicitly deleted. A destructor is only needed to release resources which can not be automatically released, such as dynamically allocated memory (using "new") or network or database connection.

(B) Destructor is called when object goes out of scope .

(C) The order of calling of Constructor is just opposite to that of Destructors.

Operator Overloading

  • In C++, we can make operators to work for user defined classes. This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading.
  • For example, we can overload an operator ‘+’ in a class like String so that we can concatenate two strings by just using +.
class Complex { 
private: 
    int real, imag; 
public: 
    Complex(int r = 0, int i =0)  {real = r;   imag = i;} 

    // This is automatically called when '+' is used with 
    // between two Complex objects 
    Complex operator + (Complex const &obj) { 
         Complex res; 
         res.real = real + obj.real; 
         res.imag = imag + obj.imag; 
         return res; 
    } 
    void print() { cout << real << " + i" << imag << endl; } 
}; 

int main() 
{ 
    Complex c1(10, 5), c2(2, 4); 
    Complex c3 = c1 + c2; // An example call to "operator+" 
    c3.print(); 
} 

Global operator overloading (using friend function)

  • Example
class Complex { 
private: 
    int real, imag; 
public: 
    Complex(int r = 0, int i =0)  {real = r;   imag = i;} 
    void print() { cout << real << " + i" << imag << endl; } 

// The global operator function is made friend of this class so 
// that it can access private members 
friend Complex operator + (Complex const &, Complex const &); 
}; 


Complex operator + (Complex const &c1, Complex const &c2) 
{ 
     return Complex(c1.real + c2.real, c1.imag + c2.imag); 
} 

For operator overloading :

  • the function call operator can't have default arguements

  • All operators except = are accessed by derived class

  • Operators ( ), [ ], -> , = can be overloaded only as member function ( not as friend function)

  • In overloading Array index operator [] operator and -> operator, we need to return a reference

  • For unary operators, the parameter list is empty except postfix + +, - - Eg.

void operator ++ (); // prefix
void operator ++ (int); // postfix
  • Advantage of using friend function for operator overloading is that - if we use member function, during execution, it creates a temporary instance of objects and may result in huge allocation of memory references

Operators that cannot be overloaded

  • Scope resolution operation (::)
  • Member access operators (*,.)
  • Ternary operator (? :)
  • Sizeof
  • Preprocessor directive (#)

Overloading operator << to print complex number-

  • Complex is a predefined class
ostream& operator << (ostream& out,Complex n){
out<<n.real;
if(n.img<0) out<<'-'<<'i';
else out<<'+'<<'i';
out<<(n.img<0? -(n.img): n.img);
return out;
}

Encapsulation

  • Encapsulation is defined as binding together the data and the functions that manipulate them, in a single unit called class .
  • Encapsulation also leads to data abstraction or hiding.

Data hiding and data abstraction

Data Hiding

  • Data hiding refers to hiding internal object details (data members). Data hiding ensures exclusive data access to class members and protects object integrity by preventing unintended or intended data alteration (or data modification). This is one of the important reason why OOP is preferred, nowadays.

  • Private members are implicitly visible ( enforce data hiding )

Data Abstraction

  • Data abstraction refers to providing only essential information about the data to the outside world, hiding the background details or implementation.

  • Consider a real life example of a man driving a car. The man only knows that pressing the accelerators will increase the speed of car or applying brakes will stop the car but he does not know about how on pressing accelerator the speed is actually increasing, he does not know about the inner mechanism of the car or the implementation of accelerator, brakes etc in the car.

  • Public members are explicitly visible ( enforce data abstraction )

Message Passing

  • Objects communicate with one another by sending and receiving information to each other.
  • A message for an object is a request for execution of a procedure and therefore will invoke a function in the receiving object that generates the desired results
  • Message passing involves specifying the name of the object, the name of the function and the information to be sent.

Member Initialisation List

  • List of members to be initialised is indicated with their constructor as a comma separated list followed by a colon. For more info, view here

  • Example

class Point { 
private: 
    int x; 
    int y; 
public: 
    Point(int i = 0, int j = 0):x(i), y(j) {}  // initialisation using member initialisation list
};
  • Used in 5 situations :-
  1. Initialisation of non-static const data members
  2. Initialisation of references
  3. initialising member objects which don't have a default constructor
  4. initialisation of base class members
  5. When constructor's parameter name is same as data member of class. (this keyword can also be used in this case, although)
  • It is better to use initialiser list for initialisation instead of assigning values in function body due to performance reasons as it directly uses the copy constructor instead of calling both the default constructor and the assignment operation. Destructor will be called in each case, though.

"this" pointer

  • The compiler supplies an implicit pointer to every non-static member function of a class, when it is called, this us called 'this' pointer. For more info, view here

  • this points to the calling object

  • this pointer is only an r-value, so its value can't be changed.

  • an object can be deleted (only if memory to it is dynamically allocated using new) by using following syntax :-

delete this;
  • Situations when this pointer is used :-
  1. When local variable's name is same as member name
  2. To return reference to the calling object (Using *this )
  3. Chaining of function calls (if it returns a reference to the object) Eg. Obj.fun1().fun2().fun3() ;
  • Type of this pointer depends on function declaration. If member function of class X is declared const, its type is const X *

Inheritance

  • The capability of a class to derive properties and characteristics from another class is called Inheritance
  • Sub Class / Derived Class: The class that inherits properties from another class is called Sub class or Derived Class.
  • Super Class / Base Class: The class whose properties are inherited by sub class is called Base Class or Super class.
  • Syntax :
class subclass_name : access_mode base_class_name
{
  //body of subclass
};
  • Various visibility modes :

Types of inheritance

  1. Single Inheritance

  2. Multilevel Inheritance :

  3. Hierarchical Inheritance :

  4. Multiple Inheritance :

  5. Hybrid inheritance :

Dreaded Diamond Problem

  • The diamond problem occurs when two super-classes of a class have a common base class ( multi-path inheritance ). For example, in the following diagram, the TA class gets two copies of all attributes of Person class, this causes ambiguities.

  • It can be resolved using any of the 2 methods :

    1. Use scope resolution operator to avoid ambiguity, but still there are 2 copies
    2. Use virtual base class so that there is only a single copy

Storage Classes

  • 5 Storage classes are there in C++

    1. Automatic

      • Default storage class for local variables
    2. Extern

      • Default storage class for global variables
    3. Static

      • A static member is shared by all objects of the class
    4. Register

      • For storing a variable in CPU registers instead of RAM, for faster access
    5. Mutable

      • Used when we want to change only a specific property or data member of a const object of a class
  • A function can have only 2 storage classes :

    1. extern
    2. static.
  • Out of these, static is possible only in member function of a class

Function Overriding

  • It is the redefinition of base class function in its derived class with same signature i.e return type and parameters. Example -
class A {  
   public: 
   void display() {   
      cout<<"Base class"; 
   } 
}; 

class B:public A {  
   public: 
   void display() {   
      cout<<"Derived Class"; 
   } 
}; 

int main() {  
   B obj; 
   obj.display();  // Output : "Derived Class"
   return 0;  
}

Virtual Functions (Runtime Polymorphism)

Pure virtual functions

  • A pure virtual function is declared in base class as virtual func() = 0;

  • It makes the base class, an abstract class. Abstract classes can't be instantiated i.e. we can't create objects of abstract classes but new classes can be derived using abstract classes.

  • Whenever a pure virtual function is present in a base class, it should be overridden in all the derived classes which should be concrete classes (have objects). If we don't do this in a derived class, it becomes an abstract class

Mechanism of virtual functions

  • Compiler silently adds a void pointer to an object of a class which contains Virtual functions

  • To accomplish late binding, the compiler creates a table called VTABLE for each class that contains Virtual functions and for the classes derived from it. The compiler places the addresses of virtual functions for that particular class in VTABLE .

  • If we don't redefine the function, it uses the address of the base class version in the derived class

  • When objects of the base class or derived class are created it secretly places a pointer, called the vpointer (VPTR) , which points to the VTABLE if its class.

  • When a function call is made through a base class pointer, the compiler inserts the code to fetch the VPTR and lookup function address in the VTABLE, thus calling the right function and causing Late Binding

  • VPTR must be initialised to point to the starting address of appropriate VTABLE (in constructor)

Constructors and destructors in inheritance

  • When an object of derived class is created, all the base class constructors are always called first, in constructor of derived class.(the reason is that only base class has access to its members, not the derived class. Moreover, base class members need to be initialised first as derived class members depend on base class)

  • Compiler calls the default constructor of base class if we don't explicitly call it in constructor of derived class.

Constructors and destructors in dynamic binding

  • When a virtual function is called within a constructor or destructor , always the member function of current class gets called (early binding) . In other words, virtual mechanism doesn't work inside a constructor or a destructor

  • Destructor can be virtual but a constructor can't be. Because once an object has been constructed, its VPTR is initialised, so the virtual function calls can take place

Dynamic type checking

  • When type checking occurs at runtime (not at compile time), it is called Dynamic type checking .

  • It occurs through RTTI (runtime time information ) mechanism in C++

  • Used in dynamic casting of pointers

Eg.

Base *b = new Derived;

Object Slicing

  • A derived class object can be assigned to a base class object (called Object Slicing) but the other way is not possible.

  • This is done at the cost of slicing of the additional data members of the derived class

  • Hence, we can call only functions of base class of a sliced object

  • It can be prevented by using pointers to class objects or by making the functions of base class as pure virtual (abstract class) as it will give compile error if you create a base class object

  • For example, view here

Size of a class object

  • Actually an object contains only the data members. Methods do not belong to any specific object. They belong to the class. All objects share one copy of methods . When you use “sizeof” operator on a class or an object you will only get the total size of the data members.

  • Private members of a class are not inherited to a child class i.e. can't be used by member functions of child class but remember that they are included while calculating size of an object of child class

  • Size of an empty class is not 0. It is 1 byte generally, to ensure that 2 different objects will have different addresses

  • If a class is derived from a virtual base class, it has a pointer to that virtual base class, even when it is empty, resulting in a a size of at least 8 bytes always

Data conversion

  • From class to fundamental data type - Use operator overloading

Eg.

class radius
{
int num;

public:
void operator float () const {
float f = 3.14 x num;
return f;
}
};
  • From fundamental to class - Use conversion constructor (parametrised constructor)

  • We can prevent this type conversions most of the times, by using the keyword explicit before the constructor. Know more here

Friend classes and friend functions

Friend classes

  • A friend class can access private and protected members of other class in which it is declared as friend. It is sometimes useful to allow a particular class to access private members of other class.

  • Example :

class Node { 
private: 
    int key; 
    Node* next; 
    friend class LinkedList; 
   // Now class  LinkedList can 
    // access private members of Node 
}; 

Friend functions

  • Like friend class, a friend function can be given special grant to access private and protected members.

  • A friend function can be any of :

    i. A method of another class

    ii. A global function

  • It can be used in 2 situations :-

    i. Operator overloading

    ii. If some particular data and functions are required to be shared between 2 or more classes

  • Drawback of friend function is that it prevents the feature of data hiding upto some extent

  • Know more here

Nested classes

  • A nested class is a class which is declared in another enclosing class. A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class, the usual access rules shall be obeyed.

Factory methods

A factory method is a method which uses dynamic memory allocation to clone itself and return a pointer to the new copy . Suppose you have a abstract class Shape and a series of derived concrete classes such as Circle, Square, Rectangle, etc. A factory method of Circle looks like

Shape * clone() 
{ 
 return new Circle(*this); // calling copy constructor 
}
  • Copy constructor can not be used to clone objects in case of polymorphism. This is true in both C++ and Java, because copy constructor does not support polymorphism . Suppose you have a method which receives a concrete-class object with a Shape handle and do something on it. Now if you want to make a copy of it in that method, with a factory method you can say
public void modifyAndDisplay(Shape * obj) 
{ 
 Shape obj1 = obj. clone(); 
 ... 
} 
  • If the passed argument is a Circle, the Shape pointer “obj” will get a Circle, if it’s Square, you will get a Square.

Templates

  • Templates are powerful features of C++ which allows you to write generic programs. In simple terms, you can create a single function or a class to work with different data types using templates.

  • 2 types :

    i. Function Template

    ii. Class Template

  • Each instantiation of function template has its own copy of local static variables. View more here

Function Template

  • A function template starts with the keyword template followed by template parameter/s inside < > which is followed by function declaration. Syntax -
template <class T>
T someFunction(T arg)
{
   ... .. ...
}
  • You can also use keyword typename instead of class in the above example
  • When, an argument of a data type is passed to someFunction( ), compiler generates a new version of someFunction() for the given data type.

Class Template

  • Syntax :
template <class T>
class className
{
   ... .. ...
public:
   T var;
   T someOperation(T arg);
   ... .. ...
};

className<dataType> classObject; // creation of object of a particular data type

Template specialisation

  • We can also specialise template to work differently, for a particular data type. Example-
// A generic sort function  
template <class T> 
void sort(T arr[], int size) 
{ 
} 

// A specialized version for char data type 
template <> 
void sort<char>(char arr[], int size) 
{ 
    // code to implement counting sort 
} 

Passing non-type parameters to templates

  • Non-type parameters must be const . The compiler must know the value of non-type parameters at compile time.
  • It is generally used for specifying max or min values or any other constant value for a particular instance of a template.

Exception Handling

  • Exceptions are run-time anomalies or abnormal conditions that a program encounters during its execution.
  • View more here

Some points to remember

  1. Extraction operator ( cin >> ) ignores whitespaces like '\n', ' ', '\t', etc. So, while taking input with whitespaces , better use getline(cin,str)

  2. If in a block a local variable of the same name as the global variable is declared, the local variable will suppress the global one from the declaration line onwards. So, to access the global variable from this block, use unary scope resolution operator "::" in front of the identifier. For more uses of scope resolution operator, view here

  3. Scope resolution operator (::) is also used, for ambiguity resolution. Ambiguity can be occurred in using the multiple inheritance when a function with the same name occurs in more than one base class.

  4. Labels are identifiers followed by a colon, eg., the case label “case 3: ” in “switch” structure. Labels are used in “switch” structure or “goto” statement to mark the location of a statement. A label (and only a label) declared inside a function is in scope everywhere in that function , in all nested blocks, before and after its own declaration.

  5. Because block is the smallest unit in C++ , most variables/identifiers are of block scope . They are local variables declared in a block.

  6. The principle of least privilege (PLP) is the idea that at any user, program, or process should have only the bare minimum privileges necessary to perform its function. In most cases it is achieved by using of qualifier const, or the private or protected access specifiers

  7. By default, elements of an array are initialised to 0.

  8. By default, arrays are passed by reference, similar to C , because name of an array is a constant pointer pointing to its first element (except when used with sizeof operator and & operator) .

  9. A class can contain a static object of self type or a pointer to self type only. It can't have an object of own type as a data member.

  10. Const keyword

  • To put "const" qualifier in front of a parameter in both the function prototype and function definition is to tell the compiler that the function doesn't modify the variable.

Eg.

void strcpy(char *, const char *);
  • A constant variable or pointer should be initialized when declared.

Eg.

const int size=4;
Report abuse