Namespaces in C++

•Namespace is simply a declarative area.
•The purpose of namespace is to localize names of identifiers to avoid name collisions.
•Elements declared in one namespace are separate from elements declared in another.
•Namespace is an important concept for library developer.
•If you include two libraries both having same function prototype, then compiler will be unable to detect which one you are referring to when you invoke it.

Syntax:
•Creating a namespace :
    namespace name{ //declarations}
•Anything defined within a namespace statement is within the scope of that namespace
•Using:
  using namespace name;
 (to include only a particular namespace defined in a library)
•using name::member
 (to include only a particular member of the namespace defined in a library)

Exception Handling in C++

Exception:

An unwanted state during the execution of the program. It can also be defined as “errors at run-time”. 
For example, 
Dividing a number by zero.

Whenever there is an exception in the program, the programmer has two possible solutions: 

a)Resumption- fix the problem and continue
b)Termination-Abort the process and return

In C++,
the Resumption model is supported by the function call mechanism, and 
the Termination model is supported by the exception-handling mechanism

Exception Handling:

“Exception Handling” allows us to manage the exception gracefully. 
Using Exception Handling technique we can avoid abnormal termination of the program and continue with the normal flow or the program, or even move the control to other parts of the program.

Exceptions are handled using try catch statements.

General syntax: 
try{ 

statements;
. . . . . 


catch(type1 arg){statements;}

catch(type2 arg){statements;}

•We can have more than one catch statement associated with a try.


Exception Handling Example:

#include<iostream.h>
void main()

      int j; 
      cin>>j; 
      try
      { 
            if(j==0) throw j; 
               int i=20/j; 
      }catch(int j){ 
            cout<<"Divide by zero"; 
      }catch(...){ 
            cout<<"Caught Exception"; 
      }
}

Output: 
Divide by zero

Re-throwing an Exception:

A re-throw is indicated by a throw without an operand. 

Example;
try{ 
      //code which throws error 
}catch(Error e){ 
      throw; //re-throw 

If a re-throw is attempted when there is no exception to throw , terminate() will be called. 
terminate(), by default, calls abort() to stop the program. But we can specify our own termination handler.

Custom Exception Class:

#include<iostream.h> 
#include<string.h> 

class MyException

{           char *msg; 
          public: 
                  MyException(){
                          msg="MyException";
                  } 
                  MyException(char *m) 
                  {
                          msg=m;
                  } 
                  char* getMessage(){ 
                          return msg;
                  } 

};

void main() 

       int age; 
       try{ 
              cout<<"Enter your age"; 
              cin>>age; 
              if(age>18) 
                     cout<<"Ready to vote"; 
              else{ 
                     MyException e("You are Minor!!"); 
                     throw e;
              } 
       } 
       catch(MyException e) 
       { 
              cout<<"Exception"<<e.getMessage(); 
       }
}

Function Overloading in C++

Function overloading is a feature of C++ that allows us to create multiple functions with the same name, so long as they have different parameters.

You can only overload functions only on the basis of:

  • Type of arguments
  • Number of arguments
  • Sequence of arguments &
  • Qualifiers like const and volatile.
Consider the following function:
        int Add(int x, int y)
       {
                return x+ y;
       }
This trivial function adds two integers. However, what if we also need to add two floating point numbers? This function is not at all suitable.Again we have to write one more function with float variables.
One way to work around this issue is to define multiple functions with slightly different names:
      int AddI(int x, int y)
     {
              return x+ y;
     }
     double AddD(double x, double y)
     {
             return x+ y;
     }

Function overloading provides a better solution
We now have two version of Add():
      int Add(int nX, int nY); // integer version
      double Add(double dX, double dY); // floating point version

Which version of Add() gets called depends on the arguments used in the call — if we provide two ints, C++ will know we mean to call Add(int, int). If we provide two floating point numbers, C++ will know we mean to call Add(double, double). In fact, we can define as many overloaded Add() functions as we want, so long as each Add() function has unique parameters.

Making a call to an overloaded function results in one of three possible outcomes:
1) A match is found. The call is resolved to a particular overloaded function.
2) No match is found. The arguments can not be matched to any overloaded function.
3) An ambiguous match is found. The arguments matched more than one overloaded function.


When an overloaded function is called, C++ goes through the following process to determine which version of the function will be called:

1) First, C++ tries to find an exact match. This is the case where the actual argument exactly matches the parameter type of one of the overloaded functions. For example:
          void Print(char *szValue);
          void Print(int nValue);

          Print(0); // exact match with Print(int)


Although 0 could technically match Print(char*), it exactly matches Print(int). Thus Print(int) is the best match available.

2) If no exact match is found, C++ tries to find a match through promotion.

To summarize,

  • Char, unsigned char, and short is promoted to an int.
  • Unsigned short can be promoted to int or unsigned int, depending on  
       the size of an int.

  • Float is promoted to double
  • Enum is promoted to int

For example:

         void Print(char *szValue);
         void Print(int nValue);
        
         Print('a'); // promoted to match Print(int)

In this case, because there is no Print(char), the char ‘a’ is promoted to an integer, which then matches Print(int).

3) If no promotion is found, C++ tries to find a match through standard conversion. 


Standard conversions include:

  • Any numeric type will match any other numeric type, including unsigned (eg. int to float)
  • Enum will match the formal type of a numeric type (eg. enum to float)
  • Zero will match a pointer type and numeric type (eg. 0 to char*, or 0 to float)
  • A pointer will match a void pointer

For example:
         void Print(float fValue);
         void Print(struct sValue);

         Print('a'); // promoted to match Print(float)


In this case, because there is no Print(char), and no Print(int), the ‘a’ is converted to a float and matched with Print(float).

Note that all standard conversions are considered equal. No standard conversion is considered better than any of the others.

Ambiguous matches:

class A


        public: 
               void foo(int x) 
               {
                  cout << "foo with one\n"; 
               } 
               void foo(int x, int y=10) 
               { 
                  cout << "foo with two\n";
               } 

}; 
int main() 


      A a; 
      a.foo(1); //error? 
}

Because function/operator overloading is resolved by compiler at compile time. So overloading a function just by providing a default argument will cause ambiguity and compiler error.

Stack Overflow Situation

func_call() {
           funct_call();
}

Every time the above function is called the return address is stored onto the stack. Calling in this infinite loop will cause a stack overflow.

Examples for an infinite loop

a. while (1)
   {
   }

b. for (;;)

   {
   }

c. do

   {
   }while(1);

d. label:
    goto label;