Вы находитесь на странице: 1из 78

Concepts in C++

Concepts in C++
Angan Adhikari

Concepts in C++
1. Variables and Storage Classes
2. Compilation and Memory Management
3. Object and Classes
4. Pointers and References
5. Inheritance and Composition
6. Constants
7. Statics
8. Functions
9. Operator Overloading
10. Polymorphism and Virtual Functions
11. Multiple Inheritance
12. Dynamic Type Information and Casting
13. Templates
14. Exceptions
15. Standard Template Library (STL)
16. Object Oriented Design Basics

Page 1 of 78
Concepts in C++

1. Variables and Storage Classes

auto Æ
- default variable type
- local to a function

static Æ
- retains the values between function calls
- initialized only once
- unavailable outside the scope of the function

extern Æ
- extern keyword tells the compiler that a variable (or function) exists, even if the
compiler has not seen it in the file currently being compiled
- forces external linkage

volatile Æ
- volatile keyword prevents the compiler from performing any optimization based
on the stability of that variable
- value of a volatile variable is always read whenever its value is required

register Æ
- variables are accessed faster
- often placed in register
- address of a register variable cannot be taken or computed i.e. the unary
address-of operator (&) cannot be used with register arrays
- register keyword cannot be used with arrays

Summary Æ

Automatic Local static Global Global static

Program (used
Visibility/
Function Function by other file File
Scope
using extern)
Lifetime Function Program Program Program
Initialization
Not initialized 0 0 0
value
Storage stack static memory static memory static memory
Retains value Variables used
Variables used Variables used
when the by several
Purpose by single by several
function functions of
function functions
terminates same file
Linkage No linkage No linkage external internal

Page 2 of 78
Concepts in C++

2. Compilation and Memory Management

C++ Compilation Process Æ

Static Data Area of a Program Æ


- followings are allocated here
1. Initialized global data and static data
2. Uninitialized global data and static data
3. Global initialized constant data
- The size of all the variables to be placed in the static memory area must be
known to the compiler at compile time for the calculation of this static memory
area.

Page 3 of 78
Concepts in C++

Stack Æ
- all the automatic variables are allocated here
- the size of the stack is limited
- works on Last In First Out (LIFO) mechanism

Heap / Free Store Æ


- This is the runtime memory area
- All the dynamically allocated objects are created here
- The program must delete these objects explictly after use

Linkage Æ
- A name is said to have linkage when it might denote the same object, reference,
function, type, template, namespace or value as a name introduced by a
declaration in another scope.
- When a name has external linkage, the entity it denotes can be referred to by
names from scopes of other translation units or from other scopes of the same
translation unit.
- When a name has internal linkage, the entity it denotes can be referred to by
names from other scopes in the same translation unit.

Page 4 of 78
Concepts in C++

- When a name has no linkage, the entity it denotes cannot be referred to by


names from other scopes.
- Linkage refers only to elements that have addresses at link/load time; thus, class
declarations and local variables have no linkage.

Namespace Æ
- The names of global functions, global variables, and classes are still in a single
global name space. The global name space can be subdivided into more
manageable pieces using the namespace feature of C++.
- An unnamed namespace can be used to make names local to a compilation unit.
The effect of unnamed namespace is very similar to that of the internal linkage.

Example:

namespace
{
class X {};
void f();
int i;
}

Here class X, function f, int i – is local to this compilation unit only.

RValue and LValue:-

Assignment is performed with the operator =. It means “take the right-hand side (often
called the rvalue) and copy it into the left-hand side (often called the lvalue). An rvalue is
any constant, variable, or expression that can produce a value, but an lvalue must be a
distinct, named variable (that is, there must be a physical space in which to store data).
For instance, you can assign a constant value to a variable ( A = 4; ), but you cannot
assign anything to constant value – it cannot be an lvalue (you can’t say 4 = A; ).

Page 5 of 78
Concepts in C++

3. Object and Classes

Structure, union and class Æ

Class structure union

default member visibilty Private Public public

default inheritance mode Private Public No Inheritance


only one member
usage constraint no constraint no constraint
at a time

Default members of a class Æ


- constructor
- copy constructor
- assignment operator (=)
- destructor
- If there are no data members in a class the C++ compiler forces the object to be
a non-zero size (typically 1 byte) because each object must have a distinct
address.

Constructor Æ
- constructor is used to initialize an object
- Like any member function, the first (secret) argument to the constructor is the
this pointer – the address of the object for which it is being called. In the case of
the constructor, however, this is pointing to an uninitialized block of memory,
and it’s the job of the constructor to initialize this memory properly.
- cannot be called explicitly
- does not return anything
- can be overloaded based on number and type of arguments
- Cannot be virtual
- A pointer to a constructor cannot be had.

Default Constructor Æ
- This constructor can be called without any arguments.
- This is the constructor with no arguments or default argument list.

Example:

C() { cout << "C():i(ii)" << endl;}


C(int ii = 10): i(ii) { cout << "C(int ii = 10)" << endl;}

Destructor Æ
- Destructor uninitializes an object
- Destructor does not take any arguments and does not return anything, destructor
cannot be overloaded.
- Destructor is called automatically when an automatic object’s scope ends.

Page 6 of 78
Concepts in C++

- Destructor is called automatically when it is destroyed through operator delete.

Singleton class Æ
- A class that assures a maximum of ONE object of its type at a given time and
provides a global access point to this object is a Singleton class.
- Singleton classes may be implemented using a protected constructor and a public
static member of that class itself.

Example:

#include <iostream>
using namespace std;

// Singleton class
class S
{
protected :
S()
{ cout << "Constructing S\n"; }

static S m_s; // static instance of class S itself

public :
static S* get_s()
{ return & m_s; }

static Show()
{ cout << "Address of object = " << &m_s << endl; }
};

S S::m_s; // definition - create object

int main()
{
cout << "main starts" << endl;
S::Show();

S *s1 = S::get_s();
cout << "s1 = " << s1 << endl;

S *s2 = S::get_s();
cout << "s2 = " << s2 << endl;

return 0;
}

Result:
Constructing S
main starts
Address of object = 0047774A
s1 = 0047774A
s2 = 0047774A

Page 7 of 78
Concepts in C++

Objects of class instantiated in heap only Æ


- This is ensured by having the constructor private and a static member function
which returns a pointer to the object created in the heap

Example:

#include <iostream>
using namespace std;

class S
{
private:
S()
{ cout << "constructing S.\n"; }

public:
static S* s_method()
{
cout << "static method called.\n";
return new S;
}
};

int main()
{
S *s1 = S::s_method();
S *s2 = S::s_method();

cout << "s1 = " << s1 << endl;


cout << "s2 = " << s2 << endl;

return 0;
}

Result:
static method called.
constructing S.
static method called.
constructing S.
s1 = 00301FF0
s2 = 00301FC0

Page 8 of 78
Concepts in C++

4. Pointers and References

Pointers, Arrays and Strings Æ


- The base address of an array is fixed but content is modifiable.
- Strings are immutable. i.e. strings declared as
char * str = “computer”;
is non-modifiable.

Pointer to class members / Pointer to members Æ


- This is a special type of pointer that points generically to a member of a class,
not to a specific instance of that member in an object.
- A pointer to a member provides an offset into an object of the member’s class at
which the member can be found.
- To access a member of a given class given a pointer to it one must use pointer-
to-member operators .* and ->*

Example :

#include <iostream>
using namespace std;

class c1
{
public:
int val;
c1(int i) {val = i;}
int double_val() {return (val + val);}
};

int main()
{
int c1::*data; // data member pointer
int (c1::*func) (); // function member pointer

data = &c1::val; // get offset of val


func = &c1::double_val; // get offset of double_val()

c1 ob(5);
c1 *pob = &ob;

cout << “value = “ << ob.*data << “\n”;


cout << “double value = ” << (ob.*func)() << “\n”;

cout << "value = " << pob->*data << "\n";


cout << "double value = " << (pob->*func)() << "\n";

return 0;
}

Result:
value = 5

Page 9 of 78
Concepts in C++

double value = 10
value = 5
double value = 10

Dangling Pointers Æ
- A pointer points to a heap-dynamic variable that has been de-allocated

Example:

#include <iostream>
using namespace std;

int main()
{
int *p;
p = new int(10);

cout << "*p = " << *p << endl;


delete p;

// Now p is a Dangling Pointer


*p = 5;
cout << "*p = " << *p << endl;

return 0;
}

- De-referencing a dangling pointer may cause the program to crash


- To avoid the problem of dangling pointers, always set a pointer to 0, after the
delete is called. Subsequent attempts to use the pointer will result in a run-time
exception.

Memory leak Æ
- A memory leak occurs when all pointers to a block of allocated memory have
been lost.
- Leaked memory cannot be accessed or reallocated
- Excessive memory leaks may cause the program to crash

Example:

#include <iostream>
using namespace std;

int main()
{
int *p;
p = new int(10);
p = new int(20);
// pointer to memory having integer value 10 is lost – memory leak

Page 10 of 78
Concepts in C++

return 0;
}

Segmentation fault Æ
- Segmentation fault occurs when there is an invalid pointer de-referencing.
"Invalid pointer" can be a NULL pointer, an un-initialized pointer, or a pointer
pointing to a piece of de-allocated memory. When you de-reference it by, say,
*ptr or by ptr->next, segmentation occurs.

new Æ
- new operator has similar functionality as malloc() in C. It performs three tasks:
1. Allocates memory for the object from the heap or free store.
2. Returns a pointer to an appropriate data type.
3. Calls the constructor for the object.

delete Æ
- Memory that is dynamically allocated using the new operator can be freed using
the delete operator. It performs two tasks:
1. Calls the destructor for the object
2. De-allocates memory back to free store
- operator delete cannot return a value
- To de-allocate dynamically allocated arrays the delete operator should be
followed by []

Example:
int *pt = new int[1024]; // allocates an array of 1024 integers
delete[] pt; // deletes the dynamic array

Placement new, delete and explicit destructor call Æ


- The new operator can be overloaded to decide where the object is going to sit in
the memory. This is called placement new
- When someone wants to destroy this object the destructor has to be called
explicitly. The normal delete operator cannot be used as the object was not
allocated in the heap.
- The overloaded operator delete that is only called if a constructor for a placement
new expression throws an exception so that the memory is automatically cleaned
up during the exception. The placement operator delete has an argument list that
corresponds to the placement operator new.
- To call default new and delete the call is qualified with global scope resolution
operator.

Syntax:
X *px = ::new X();
::delete px;

Example:

#include <cstddef> // size_t


#include <iostream>

Page 11 of 78
Concepts in C++

using namespace std;

class X
{
int i;
public:
X(int ii = 0) : i(ii)
{
cout << "X::X() : this = " << this << endl;
// throw "some_exception";
// placement delete is called when exception is thrown
}

~X()
{ cout << "X::~X() : this = " << this << endl; }

// overloaded new operator : placement new


void* operator new(size_t n, void* loc)
{
cout << "operator new : " << endl;
cout << "size = "<< n << endl;
return loc;
}

// overloaded delete operator : corresponding placement delete


void operator delete( void *p1 , void *p2 )
{
cout << "operator delete : " << endl;
cout << "p1 = " << p1 << endl << "p2 = " << p2 << endl ;
((X*)p1)->X::~X(); // Explicit destructor call
return;
}
};

int main()
{
int a[10];
cout << "a = " << a << endl;

try
{
X* px = new(a) X(50); // Place X at location a
px->X::~X(); // Explicit destructor call
}
catch (const char * some_string)
{
cout << "catch : " << some_string << endl;
}

return 0;
}

Page 12 of 78
Concepts in C++

Result (with no exception):


a = 0x241ff30
operator new :
size = 4
X::X() : this = 0x241ff30
X::~X() : this = 0x241ff30

Result (with exception thrown by constructor):


a = 0x241ff30
operator new :
size = 4
X::X() : this = 0x241ff30
operator delete :
p1 = 0x241ff30
p2 = 0x241ff30
X::~X() : this = 0x241ff30
catch : some_exception

Reference and Pointer Æ


- A pointer is variable that stores addresses and a reference (&) is like an alias to
an existing variable

Example:

int i = 3; // integer declaration

int * pi = &i; // pi points to the integer i


int& ri = i; // ri is refers to integer i – creation of reference and initialization

int& ri = 10; // Error: non const reference ri cannot refer to a constant


const int& ri = 10; // ok

- A const reference can refer to a const int. It is done with a temporary variable
with value of the const and then the initialization of reference with that variable.
This temporary variable persists until the end of its reference’s scope.
- Array of references cannot be created as each reference in the array cannot be
initialized at the time of creation.
- A pointer can point to many different objects during its lifetime; a reference can
refer to only one object during its lifetime i.e. a reference cannot be rebound.
- References, unlike pointers, have to be initialized at the point of definition

Page 13 of 78
Concepts in C++

- One has to use an explicit operator (* operator) to de-reference a pointer, but no


operator is needed to de-reference a reference
- Constant pointers differ from references in one subtle but significant way. A valid
reference must refer to an object; a pointer need not.
- A pointer, even a const pointer, can have a NULL value. A null pointer doesn't
point to anything. But a valid reference cannot be NULL.
- The following piece of codes may produce invalid references

// Sample 1
int* p;
...
int& r = *p; // reference r is bound to the object p points to – can be NULL

// Sample 2
int& f() // function f returns a reference to integer i
{
int i;
...
return i; // storage of i vanishes as the function returns
}

Example:

#include<iostream>
using namespace std;

int main()
{
int i = 10;
int &ri = i;

cout << "&i = " << &i << endl;


cout << "ri = " << ri << endl;
cout << "&ri = " << &ri << endl;

return 0;
}

Result:
&i = 0x7f7f06a8
ri = 10
&ri = 0x7f7f06a8

Pass by Reference and Pass by Pointer Æ

Sender's Sender Actual Receiver's Receiver


Passed by
Declaration Access Parameter Declaration Access

Tx x.f() x T& y y.f() reference

T *x x->f() *x T& y y.f() reference

Page 14 of 78
Concepts in C++

Tx x.f() &x T* y y->f() pointer


T *x x->f() x T* y y->f() pointer

Example:

#include <iostream>
#include <string>
using namespace std;

void swap1(int& , int& ); // takes arguments my reference


void swap2(int* , int* ); // takes arguments my pointer
void swap3(int* , int* ); // takes arguments my pointer

void swap1(int& a, int& b)


{
int temp = a;
a = b;
b = temp;
}

void swap2(int* a, int* b)


{
int temp = *a;
*a = *b;
*b = temp;
}

void swap3(int* a, int* b)


{
int *temp = a;
a = b;
b = temp;
}
// This cannot swap
// Passing by pointer only gets an address copy

class C
{
public:
int m,n;
C(): m(1),n(2) {}
void show() const
{
cout << "m = " << m << endl;
cout << "n = " << n << endl << endl;;
}

};

int main()

Page 15 of 78
Concepts in C++

{
C x;
int *p = &(x.m);
int *q = &(x.n);

x.show();

swap1(x.m,x.n); // pass by reference


x.show();

swap1(*p,*q); // pass by reference


x.show();

swap2(&(x.m), &(x.n)); // pass by pointer


x.show();

swap2(p,q); // pass by pointer


x.show();

swap3(&(x.m), &(x.n)); // pass by pointer


x.show();

return 0;
}

Result:
m=1
n=2

m=2
n=1

m=1
n=2

m=2
n=1

m=1
n=2

m=1
n=2

Page 16 of 78
Concepts in C++

5. Inheritance and Composition

Visibility modes or Access Specifiers Æ


public - anyone can access
private - only member can access
protected - Inherited classes can access

Visibility after inheritanceÆ

Derived class visibility


Base class
visibility Public Private Protected
Derivation Derivation(default) Derivation
Private Not visible Not visible Not visible
Protected Protected Private Protected
Public Public Private Protected

Public Inheritance Æ
- Normally the inheritance is done as public so that interface of the base class is
also an interface of the derived class.

Private Inheritance Æ
- In private inheritance all the data member and functionality of the base class is
hidden
- To make the public members of the base class visible in the derived class the
names of those members have to be specified in the public section of the derived
class without any arguments or return values

Example:

#include <iostream>
using namespace std;

class B
{
public:
char f1() const { return 'a'; }
int f2() const { return 2; }
float f3() const { return 3.0; }
float f3(int) const { return 4.0; }
};

class D : B // Private inheritance


{
public:
using B::f1; // Name publicizes member
using B::f3; // Both members exposed

Page 17 of 78
Concepts in C++

};

int main()
{
D d;
d.f1();
// d.f2(); // Error: private member function
d.f3();
d.f3(1);

return 0;
}

Protected Inheritance Æ
- Protected inheritance is done to make the base class interface available to
derived classes and friends

Things those are not inherited Æ


- Constructor
- Destructor
- Copy constructor
- Assignment operator
- friendship

Pointer Æ
- The pointer to a base class can contain the address of a derived class object
- The pointer to a derived class cannot contain the address of a base class object

Constructor rule for inheritance Æ


- Constructor of base class cannot be inherited.
- If a base class has at least one constructor that requires parameter, and no
default constructor is defined for that base class, then the constructor of the
derived class must pass parameters to any one base class constructor. There is
no need to pass parameters explicitly if a base class has a default constructor. It
will be called automatically.
- The constructor of the base is always called before the derived class constructor

Copy constructor rule for inheritance Æ


- The copy Constructor of a derived class calls the copy constructor of the base
class first and then the copy constructor of its own class.
- If the derived class does not have a user-defined copy constructor and base class
has a user-defined copy constructor, the base class user-defined copy constructor
is called first and then the default copy constructor of derived class.

Destructor rule for inheritance Æ


- destructors of the base classes cannot be inherited.
- destructors for derived classes should only do clean up required for itself

Page 18 of 78
Concepts in C++

- destructors for derived classes should not worry about clean up related to
inherited properties
- destructor of base class is automatically called after the destructor of derived
class.

Name Hiding Æ
- When a class is inherited and one member function is given a new definition,
there are two possibilities

1. Signature and the return type remains the same


• Function Redifinition (for ordinary member functions)
• Function Overriding (for virtual member functions)

2. Signature and the return type changes


• Name Hiding

- Anytime a function is given a new definition in the derived class, all the other
versions are automatically hidden in the new class
- Overloading is not possible across scopes

Example:

#include <iostream>
#include <string>
using namespace std;

class Base
{
public:
int f()
{ cout << "Base::f()\n";
return 1;
}

int f(string) // overloaded function


{ return 1;}

void g(){}
};

class Derived1 : public Base


{
public:
void g() {}
};

class Derived2 : public Base


{
public:
int f() // redefinition
{ cout << "Derived2::f()\n";
return 2;

Page 19 of 78
Concepts in C++

}
};

class Derived3 : public Base


{
public:
void f() // change in return type – name hiding
{ cout << "Derived3::f()\n";}
};

class Derived4 : public Base


{
public:
int f(int) // change argument list – name hiding
{ cout << "Derived4::f()\n";
return 4;
}
};

int main()
{
string s("C++");

Derived1 d1;
int x = d1.f();
d1.f(s);

Derived2 d2;
x = d2.f();
//d2.f(s); // Error: string version hidden

Derived3 d3;
d3.f();
//x = d3.f(); // Error: return int version hidden

Derived4 d4;
//x = d4.f(); // Error: f() version hidden
x = d4.f(1);

return 0;
}

Result:
Base::f()
Derived2::f()
Derived3::f()
Derived4::f()

Finalizing a class Æ
- This is a way of preventing any other inheritance from a particular class.
- It relies on the fact that the most derived class in a hierarchy must construct a
virtual base

Page 20 of 78
Concepts in C++

Example:

#include <iostream>
using namespace std;

class Usable; // final class

class Usable_lock // dummy class


{
friend class Usable; // declare the final class as a friend
private:
Usable_lock() {} // private constructor
Usable_lock(const Usable_lock&) {} // private copy constructor
};

class Usable : public virtual Usable_lock // public virtual inheritance


{
public:
Usable();
Usable(char*);
};

class DD : public Usable { }; // Inheritance

int main()
{
Usable u1; // ok

// DD dd; // error: DD::DD() cannot access


// Usable_lock::Usable_lock() - a private member
return 0;
}

return efficiency
When new objects are created to return by value, notice the form used. In
operator+, for example:

return Integer(left.i + right.i);

This may look at first like a “function call to a constructor,” but it’s not. The
syntax is that of a temporary object; the statement says “make a temporary
Integer object and return it.” Because of this, you might think that the result
is the same as creating a named local object and returning that. However, it’s
quite different. If you were to say instead:

Integer tmp(left.i + right.i);

Page 21 of 78
Concepts in C++

return tmp;

three things will happen. First, the tmp object is created including its
constructor call. Then, the copy-constructor copies the tmp to the location of
the outside return value. Finally, the destructor is called for tmp at the end
of the scope.

In contrast, the “returning a temporary” approach works quite differently.


When the compiler sees you do this, it knows that you have no other need
for the object it’s creating than to return it so it builds the object directly into
the location of the outside return value. This requires only a single ordinary
constructor call (no copy-constructor is necessary) and there’s no destructor
call because you never actually create a local object. Thus, while it doesn’t
cost anything but programmer awareness, it’s significantly more efficient.

Page 22 of 78
Concepts in C++

Constants

Const correctness Æ
- the keyword const provides features that can help you create more robust and
bug-free applications. This is called const correctness

Constant folding Æ
- This is the replacement of the const variable with its value (if available at compile
time) by the compiler wherever it is found in the file
- The difference between the macro (#define) and constant folding is the former
is replaced by value by the preprocessor and the later is done by compiler –
hence type checking is done here.

Example:

int *p = new int; // p gets a value only at runtime


const int i = (int)p;

Here the constant folding cannot take place at compile time but the code compiles
without any errors.

Linkage Æ
- C defaults to external linkage of const and storage is always created
- C++ defaults to internal linkage of const and does not necessarily create
storage. When defined as extern the storage is created for const
- In C++ the const that is outside all functions has got a file scope

extern const int x = 1; // definition: allocates storage and constant folding


// also takes place within the file

extern const int x; // declaration: does not allocate storage and constant
// folding cannot take place within the file as it does not
// know the value

Character Array Literals Æ


- Character array literals are treated by the compiler as a constant character array

Example:
char *str = “California”;
const char *str = “California”; // same effect

const in Aggregates Æ
- Storage is allocated for constant aggregates
- the value cannot be used at compile time because the compiler is not required to
know the contents of the storage at compile time.

Example:

Page 23 of 78
Concepts in C++

// constants and aggregates


#include <iostream>
using namespace std;

int k = 10; // memory allocation


// int a[k]; // Error: value of index of global array has to be known at
// compile time

// const int x; // Error: constant has to be initialized when declared


// static const int k; // Error: constant has to be initialized when declared

const int m = 50; // memory allocation – constant folding


int b[m]; // ok: value of m known at compile time

const int i[] = { 1, 2, 3, 4 }; // memory allocation for aggregates


// float f[i[3]]; // Error: value of array index has to be known

int main()
{
int p; // p is initialized to some garbage value
int c[p]; // ok:

return 0;
}

Passing by constant value Æ


- Arguments passed to the function does not change within the function

Example:
void func(const int a)
{
// a++; // Illegal
}

Returning by constant value for built-in types Æ


- Returning by constant value has got no effect for built-in types

Example:

// returning consts by value


// has no meaning for built-in types

#include <iostream>
using namespace std;

int f3() { return 1; }


const int f4() { return 1; }

int main()
{
const int j = f3(); // Works fine

Page 24 of 78
Concepts in C++

int k = f4(); // But this works fine too

return 0;
}

Returning by constant value for class objects Æ


- If a function returns a class object by value as a const, the return value of that
function cannot be an l-value ,that is, it cannot be assigned to or otherwise
modified.

Example:

// Constant return by value


// Result cannot be used as an l-value
#include <iostream>
using namespace std;

class X
{
int i;
public:
X(int ii = 0);
void modify();
};

X::X(int ii) { i = ii; }


void X::modify() { i++; }

X f5() { return X(); }


const X f6() { return X(); }
void f7(X& x) { x.modify(); }

int main()
{
f5() = X(1); // ok – but not recommended - probably a bug
f5().modify(); // ok – but not recommended - probably a bug

f7(f5()); // ok
// f6() = X(1); // Error: reassignment of constant
// f6().modify(); // Error: modification of constant object
// f7(f6()); // Error: f7() does not take const reference

return 0;
}

The function f5() returns a non-const X object. But in the expression


f7(f5());
the compiler must manufacture a temporary object to hold the return value of f5()
so it can be passed to f7(). This would be fine if f7() took its argument by value;
then the temporary would be copied into f7() and it wouldn’t matter what happened
to the temporary X. However, f7() takes its argument by reference, which means in
this example takes the address of the temporary X. Since f7() doesn’t take its

Page 25 of 78
Concepts in C++

argument by const reference, it has permission to modify the temporary object. But
the compiler knows that the temporary will vanish as soon as the expression
evaluation is complete, and thus any modifications you make to the temporary X will
be lost. By making all temporary objects automatically const, this situation
causes a compile-time error.

Passing and returning address Æ

Example:

// Constant pointer argument/return


void t(int*) {}

void u(const int* cip)


{
// *cip = 2; // Illegal - modifies value
int i = *cip; // ok - copies value
// int* ip2 = cip; // illegal: non-const
}

const char* v()


{
// Returns address of static character array
return "result of function v()";
}

const int* const w()


{
static int i;
return &i;
}

int main()
{
int x = 0;
int* ip = &x;
const int* cip = &x;
t(ip); // ok
// t(cip); // Error
u(ip); // ok
u(cip); // ok
// char* cp = v(); // Error
const char* ccp = v(); // ok
// int* ip2 = w(); // Error
const int* const ccip = w(); // ok
const int* cip2 = w(); // ok
// *w() = 1; // Error

return 0;
}

Page 26 of 78
Concepts in C++

Passing const reference Æ


- To allow temporaries to be passed to functions by reference, the argument must
be a const reference.

Example:

// Temporaries are const


#include <iostream>
using namespace std;

class X {};

X f() { return X(); } // Return by value


void g1(X&) {} // Pass by non-const reference
void g2(const X&) {} // Pass by const reference

int main()
{
// g1(f()); // Error: const temporary created by f():
g2(f()); // ok - g2 takes a const reference

return 0;
}

Pointer to const Æ
const int * u; // u is a pointer that points to constant int
int const * v; // v is a pointer that points to constant int

const pointerÆ
int d = 1; // declare integer
int * const w = &d; // w is a constant pointer to an int

const int * const x = &d; // x is a constant pointer to a constant int


int const * const y = &d; // y is a constant pointer to a constant int

Note: -
1. Constant pointer to an integer takes assignment of int pointer as well as
constant integer pointer.
2. To allow temporaries to be passed to functions by reference, the argument
must be a const reference.

Constant in classes and Constructor Initializer listÆ


- Constant within a class implies that storage will be allocated for that variable
within each object and this represents a value that is initialized once and cannot
be changed
- The use of constant in a class means that the value will not change for the
lifetime of that object. However, each object may contain different value for that
constant
- For non static constants inside a class the initialization cannot be done within the
class

Page 27 of 78
Concepts in C++

- The constants in a class can be initialized in the constructor initializer list

Example:

#include <iostream>
using namespace std;

class A
{
const int i;
// const int i = 5; // Error: initialization not possible
public:
A(int x):i(x){}
};

int main()
{
A a(5);
return 0;
}

Compile time constant in classes or in-class constants Æ


- static const of a built-in type is treated as a compile time constant – no memory
allocation is done – constant folding
- The value of this member of a class does not change and there is only one
instance, irrespective of the number of objects created
- static const member must be initialized when defined
- Same effect can be had using enum declaration

Example:

#include <iostream>
using namespace std;

class C
{
static const int a = 1024;
enum{ b = 19 };

// const int x = 1024; // Error : not static


// static int y = 1024; // Error : not const
};

Constant member function Æ


- most general form of member function – both constant and non constant objects
of the class can access these functions freely.
- The keyword const must be repeated in the definition.
- does not modify member data
- neither constructors nor destructors can be constant member function as they
always perform some modifications on the object during initialization and cleanup

Page 28 of 78
Concepts in C++

Syntax:
int func(int a) const
{ ..... }

Constant objects Æ
- No data members of the object are changed during the lifetime of the object
- When a member is declared as constant the compiler is told that it will be called
for constant objects
- A non constant member function is treated as one that will modify data members
in an object, and the compiler does not allow to call that non constant function
for a constant object.

mutable Æ
- Mutable is a C++ keyword that specifies that a member may be updated or
modified even if it is a member of a const object. The constant member functions
can change mutable members.

Example:

#include <iostream>
using namespace std;

class Animal
{
private:
mutable int age; // mutable member
public:
Animal(int a) {age = a;}
void setAge(int newage) const {age = newage;}
};

int main()
{
const Animal Tiger(3); // constant object
Tiger.setAge(4);
return 0;
}

Note:-If you declare a member function const, you tell the compiler the function
can be called for a const object. A member function that is not specifically
declared const is treated as one that will modify data members in an object, and
the compiler will not allow you to call it for a const object

explicit Æ
- This keyword is a declaration specifier that can only be applied to in-class
constructor declarations.
- Constructors declared explicit will not be considered for implicit conversions.
- It is meaningless to apply explicit to constructors with multiple arguments, since
such constructors cannot take part in implicit conversions.

Page 29 of 78
Concepts in C++

Example:

#include <iostream>
using namespace std;

class X
{
public:
explicit X(int) // explicit constructor
{ cout << "X::X() called.\n" ; }
};

class Y
{
public:
Y(int)
{ cout << "Y::Y() called.\n" ; }
};

void f1(X)
{ cout << "f(X) called.\n" ; }

void f2(Y)
{ cout << "f(Y) called.\n" ; }

int main()
{
int i = 10;

// f1(i); // Error : there is no available implicit conversion from int to X


f2(i); // this is ok : imlpicit conversion takes place from int to class Y

return 0;
}

Result:
Y::Y() called.
f(Y) called.

Page 30 of 78
Concepts in C++

6. Statics

Static variables inside functions Æ


- When a static object is created inside a function, the storage of this object is not
on the stack but instead program’s static data area.
- The initialization of the local static data is done only when the control comes for
the first time.

Static data member Æ


- Static data has got single piece of storage irrespective of the number of objects
created
- For all the derived classes also the static member has the same memory location
as the base one.
- The size of the static data member does not come into account when the size of
the object is calculated
- Static data members can be accessed by any member function
- The statics default to internal linkage. The compiler does not allocate storage
for static members when declared. The linker reports an error if a static member
is accessed with declaration but without definition.
- The definition of a static data member must be:
1. done only once
2. outside the class
3. cannot be inline

Example:

#include <iostream>
using namespace std;

class A
{
static int i; // declaration
static int j; // declaration
};

int A::i = 1; // definition


int A::j; // definition – automatically initialized to zero

Static member function Æ


- operates on the class in general, rather than on objects of the class
- They do not have this pointer
- They cannot access ordinary data members. They operate on static data
members.
- static member functions can call only static member functions.
- Cannot be virtual
- It can be called with class name and the scope resolution operator

Syntax:
someclass :: some_static_function();

Page 31 of 78
Concepts in C++

Static objects Æ
- The static objects of user-defined types must be initialized with constructor calls.
i.e. either with default constructors or with constructor argument list
- Static objects within function are initialized when the control passes through the
definition for the first time.
- The constructor for a global static object is called before main() is entered
- The static objects (both local and global) are destroyed when the main()
terminates. The destructors are called in a reverse order.

Example:

#include <iostream>
using namespace std;

class X
{
char c;
public:
X(char cc = 'a') : c(cc) // Default Constructor
{ cout << "X::X() for " << c << endl; }

~X() // Destructor
{ cout << "X::~X() for " << c << endl; }
};

void f()
{
cout << "Called f()" << endl;
static X x1('b');
static X x2; // Default constructor required
cout << "Returning from f()" << endl;
}

static X x3('c'); // Global static object

int main()
{
cout << "main() starts" << endl;
f();
cout << "main() ends" << endl;
return 0;
}

Result:
X::X() for c
main() starts
Called f()
X::X() for b
X::X() for a
Returning from f()
main() ends
X::~X() for a

Page 32 of 78
Concepts in C++

X::~X() for b
X::~X() for c

Named Constructor Æ
- With the Named Constructor Idiom, all the class's constructors are declared in
the private or protected sections, and public static methods are provided that
return an object. These static methods are the so-called "Named Constructors."
In general there is one such static method for each different way to construct an
object.

Example:

#include <cmath> // To get sin() and cos()


#include <iostream>
using namespace std;

#include <stdio.h>

class Point
{
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};

inline Point::Point(float x, float y): x_(x), y_(y)


{}

inline Point Point::rectangular(float x, float y)


{ return Point(x, y); }

inline Point Point::polar(float radius, float angle)


{ return Point( radius*cos(angle), radius*sin(angle) ); }

int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
return 0;
}

Statics within Nested and Local classes Æ


- Nested class can have static data members
- Local class cannot have static data members

Example:

Page 33 of 78
Concepts in C++

#include <iostream>
using namespace std;

class Outer
{
class Inner
{
static int i; // declaration
};
};

int Outer::Inner::i = 1; // definition

void f()
{
class Local
{
public:
// static int i; // Error : definition is impossible
} x;
}

int main()
{
Outer x;
f();
return 0;
}

Page 34 of 78
Concepts in C++

7. Functions

Function call Æ
- During a function call the followings are pushed into the stack in the following
order and popped from the stack in the reverse order
1. function arguments from right to left
2. return address
3. local variables

Restrictions on main function Æ


- Cannot be declared as inline
- Cannot be declared as static
- Cannot have its address taken

Function Pointers Æ
- function pointer contains address of a function

Example:

#include <iostream>
using namespace std;

void func() { cout << "func() called" << endl; }

int main()
{
void (*fp)(); // Define a function pointer
fp = func; // Initialize it
(*fp)(); // Dereferencing calls the function

void (*fp2)() = func; // Define and initialize


(*fp2)();

return 0;
}

Result:
func() called
func() called

Page 35 of 78
Concepts in C++

Function overloading Æ
- A function can be overloaded on the number of arguments and the type of the
arguments within the same scope.
- A function cannot be overloaded on the return type only, as it is not mandatory
to take the return value of a function.

Name Mangling / Function Decoration Æ


- The process of encoding the parameter types with the function name into a
unique name during compilation is called name mangling or function decoration.
The inverse process is called demangling.
- The return type is not taken into account while name mangling
- GNU C++ compiler mangles a member function by emitting function name,
followed by __, followed by encodings of any function qualifiers (e.g const),
followed by function’s class, followed by mangling of the parameters, in order.

Example:

Foo::bar(int, long) const Æ bar__C3Fooil


Foo::Foo(int, long) const Æ __C3Fooil

For constructor function name is left out

- To avoid name mangling for C functions (from a C Library) used in C++ code the
compiler can told explicitly to perform the C Linkage (without mangling) using
extern keyword.

Example:
extern "C" float f(int a, char b); // C Linkage without name mangling

Disadvantages of Macro compared to functions Æ


- works on text substituiton mechanism by the preprocessor unlike normal
functions where assembly-language CALL and RETURN are used
- preprocessor macros cannot access class member data and hence they cannot be
used as class member functions
- generally confined to functions that can be expressed in a single statement.
- no type checking is done for macros

Inline function Æ
- C++ implements macro as inline function
- Function definition inside a class definition is automatically inline
- Inline function is expanded in place, like a preprocessor macro so that overhead
of function call is eliminated
- The keyword inline is just a suggestion to the compiler to make the function
inline. There are cases when the inilining cannot be performed:
1. Compiler cannot perform inlining if the function is too complicated
2. Compiler cannot perform inlining if the addess of the function is taken
implicitly or explicitly. If the compiler must produce an address, then it will
allocate storage for the function and use the resulting address.
3. Compiler does not perform inlining if are static variables used in the function

Page 36 of 78
Concepts in C++

4. Compiler does not perform inlining if there is a recursive function call


- inline functios have internal linkage. The keyword extern has no significance
when used with inline functions

Default arguments Æ
- default arguments are provided in the function declaration
- functions declared with default arguments can be called without any parameters

Syntax:
void func(int i=5, char c=’A’);

Friend function Æ
- these functions can operate on objects of two different classes and can access
private data members of both
- classes can also be friends
- friendship is not inherited
- friend functions are not members of a class.
- friend functions do not have this pointer.

Copy constructor Æ
- This is provided automatically by the compiler for every object
- copy constructor creates a new object and performs a member by member copy
- the difference between copy constructor and assignment operator is that copy
constructor creates a new object
- in the copy constructor the argument must be passed by reference X(const X&),
which creates no copies. Otherwise, the copy constructor calls itself and the
compiler runs out of memory.
- The copy constructor is invoked when an object is passed by value to a function
- The copy constructor is invoked when a value is returned from a function
- To avoid copying the copy constructor and the assignment operator can be
overloaded as private members
- both the statements

someclass object1(object2); // copy initialization


someclass object1 = object2; // copy initialization

use the default copy constructor.

Return Value Optimization (RVO) Æ


- This is a special feature some compiler to optimize the redundant construction
during function return by value

Example:

#include <iostream>
using namespace std;

class X
{

Page 37 of 78
Concepts in C++

public:
X() // Constructor
{ cout << "X::X()" << endl; }

X(const X&) // Copy Constructor


{ cout << "X::X(X&)" << endl; }
};

X f1()
{
cout << "f1()" << endl;
X x;
return x;
}

X f2()
{
cout << "f2()" << endl;
return X();
}

int main()
{
f1();
cout << endl;
f2();
return 0;
}

Result (GNU Compiler g++):


f1()
X::X()
X::X(X&)

f2()
X::X()

Shallow copy of objects Æ


- Shallow copy is one that makes an exact replica of the source object. For
example, all references to other objects are copied exactly.
- The pointers are copied, but the memory they point to are not copied - the field
in both the original object and the copy point to the same dynamically allocated
memory
- The default copy constructor and assignment operator make shallow copies
- When the copy constructor or the assignment operator is overloaded the default
functionality of shallow copying is hidden and the user defined functionality gets
into action

Deep copy of objects Æ


- Deep copy copies the source object, and all objects that the source references.

Page 38 of 78
Concepts in C++

- A deep copy copies all fields, and makes copies of dynamically allocated memory
pointed to by the fields
- A class that requires deep copies will generally need:
• An overloaded copy constructor to make a copy of the dynamically allocated
memory.
• An overloaded assignment operator to make a copy of the dynamically
allocated memory.
• A destructor to delete the dynamically allocated memory

Summary of function behavior Æ

Will
Is Function Can Compiler
Can Is Function
Function Inherited Function Generate
Function Be a Member
Type from Base Return a Function if
Virtual? or Friend?
Class? Value? User Does
Not?

Constructor No No No Member Yes

Copy
No No No Member Yes
Constructor

Destructor No Yes No Member Yes

Assignment
No Yes Yes Member Yes
(operator =)

Conversion Yes Yes No Member No

operator Static
Yes No void* No
new member

Page 39 of 78
Concepts in C++

operator Static
Yes No void No
delete member
Other
member Yes Yes Yes Member No
functions
Friend
No No Yes Friend No
functions

Page 40 of 78
Concepts in C++

7. Operator Overloading

Operator Functions Æ
- Functions defining meanings for the following operators can be declared

+ - * / % ^ &
| ~ ! = < > +=
-= *= /= %= ^= &= |=
<< >> >>= <<= == != <=
>= && || ++ -- ->* ,
-> [] () new new[] delete delete[]

Operators that cannot be overloaded Æ


- . (member access operator)
- .* (pointer to member operator)
- :: (scope resolution operator)
These operators take a name, rather than a value, as their second operand and
provide the primary means of referring to members. Overloading them can lead to
confusions.

- ?: (conditional operator)
- sizeof (sizeof operator)
- typeid (type identification operator)

The general reason for this restriction is safety. If these operators are overloaded the
safety mechanism may be broken and existing practice may become confusing.

Global scope resolution operator (::) Æ


- It permits a program to reference an identifier in the global scope that has been
hidden by another identifier with the same name in the local scope.

Difference between overloaded operator and function call Æ


- the syntax is different
- the compiler determines which function to call when it spots the right pattern

Rules for operator overloading Æ


- It is not possible to change the precedence, grouping, or number of operands of
operators.
- An overloaded operator always requires one less argument than its number of
operands.
- Operator functions can be called explicitly to implement operators.
- Except for assignment operator (=), Operator functions are inherited. But the
inherited operator functions can still handle only the base class objects.
- Overloaded operators cannot have default arguments
- Predefined meaning of an operator for the built-in types may not be changed
- New operator tokens cannot be added
- Identities among operators applied to basic types

Page 41 of 78
Concepts in C++

assignment operator = Æ
- Operator = must be a non-static member of a class. It does not get inherited.
- Every class has a default operator =, unless it is redefined by the class. The
default operator is defined as member wise assignment of each member of the
class. The definition is
X& operator = (const X&)
- Assignment operator resembles constructors and destructors more than in
resembles operators such as += or ++.
- When the default assignment operator (provided by compiler) of a derived class
is invoked, the assignment operator of the base class if defined is called
implicitly.
- If the base class assignment operator is not defined then the default assignment
operator is called.

Example:

#include <iostream>
using namespace std;

class B
{
public:
B& operator =(const B&) // overloaded assignment operator
{ cout << "B::=()" << endl; }
};

class D1 : public B
{
public:
D1& operator =(const D1&) // overloaded assignment operator
{ cout << "D1::=()" << endl; }
};

class D2 : public B
{
};

int main()
{
B b1, b2;
D1 x1, x2;
D2 y1, y2;

b1 = b2;
x1 = x2;
y1 = y2;

b1 = x1;
b1 = y1;
// x1 = b1; // Error
// x1 = y1; // Error
// y1 = x1; // Error

Page 42 of 78
Concepts in C++

// y1 = b1; // Error

return 0;
}

Result:
B::=()
D1::=()
B::=()
B::=()
B::=()

Function call operator () Æ


- A function call operator is considered as a binary operator with the primary
expression as the first operand and the expression list as the second argument.
- Must be a non-static member function i.e. Cannot be a friend or a global function
- A call x(arg1, arg2) is interpreted as x.operator(arg1, arg2) for class object x.

Increment and Decrement operators Æ


- Function operator ++ taking one argument defines the prefix increment
operator ++ for objects of a class.

Example:
class X
{
public:
operator ++();
};

void f(X a)
{
++a; // a.operator++()
}

- A function operator ++ taking two arguments defines the postfix increment


operator ++ for objects of a class.
- The second argument for the postfix operator must be of type int. It is used only
to distinguish between prefix and postfix.
- For a postfix increment, expression will have the second argument as 0.

Example:
class X
{
public:
operator ++ (int);
};

void f(X a)
{
a++ ; // a.operator ++ (0);
}

Page 43 of 78
Concepts in C++

De-referencing operator / Smart Pointers Æ


- Operator -> can be defined as a unary postfix operator
- Primarily used for creating smart pointers – objects that act like pointers
- Operator -> must be a member function. Its return type must be a pointer or an
object of the class.

Example:

#include <iostream>
using namespace std;

class X
{
public:
int j;
};

template<class T> // template class


class Smart_Ptr
{
int i;
T* px;
public:
Smart_Ptr(int ii): i(ii){}
~Smart_Ptr(){}
T* operator ->() // overloaded operator ->
{
cout << "overloaded operator ->" << endl;
return px;
}
};

void user(int k)
{
Smart_Ptr<X> spx(k);
spx->j = k;
cout << "spx->j = " << spx->j << endl;
}

int main()
{
user(23);
return 0;
}

Result:
overloaded operator ->
overloaded operator ->
spx->j = 23

Page 44 of 78
Concepts in C++

Conversion from built-in types to user-defined types Æ


- done using constructor

Example:
char * Æ string
use constructor taking built-in type as argument – implicit conversion

Conversion from user-defined type to built-in types Æ


- done with overloaded casting operator
- converts an object of a class of which it is a member

Example:
string Æ char *
operator char*()
{

Conversion from user-defined type to user-defined Æ


- Two ways
1. using overloaded casting operator
2. using constructor

objA = objB
// where objB is source type and objA is destination type.

Case 1:
Overloaded casting operator is defined in source class which return destination class

Case 2:
Constructor of destination class takes source type as argument, converts destination
class type to source type.

Example:

#include <iostream>
using namespace std;

class B;

class A // destination class


{
public:
int a;
A(int i=0): a(i){}
int get(){ return a; }

/*
A(B temp_b) // destination class constructor
// taking source object and assigning

Page 45 of 78
Concepts in C++

{
cout << "Conversion constructor called" << endl;
a = temp_b.get();
}
*/
};

class B // source class


{
int b;
public:
B(int i): b(i) {}
int get(){ return b; }

operator A () // source class uses overloaded casting operator


{
cout << "Overloaded casting operator function" << endl;
temp_a;
temp_a.a = b;
return temp_a;
}
};

int main()
{
A objA(1);
B objB(2);

objA = objB;
cout << "objA::a = " << objA.get() << endl;;

return 0;
}

Result:
Overloaded casting operator function
objA::a = 2

Summary of Data type Conversions Æ

Conversion takes place in


Conversion
Source class Destination class

Built-in Æ User-defined Not applicable Constructor

User-defined Æ Built-in Casting Operator Not applicable

User-defined Æ User-defined Casting Operator Constructor

Page 46 of 78
Concepts in C++

8. Polymorphism and Virtual Functions

Compile Time Polymorphism or Early Binding or Static Binding Æ


- An object is bound to its function call at compile time.
- Implemented using overloaded functions and operators
- Main advantage is efficiency

Run Time Polymorphism or Late Binding or Dynamic Binding Æ


- Function calls are not resolved until run time
- Implemented using virtual functions
- Main advantage is flexibility

Virtual Function Æ
- Keyword virtual tells the compiler to enforce late binding of the function when the
address of the base class is used
- The inhertance from the base class to the derived class must be public
- A call to a virtual function is resolved according to the underlying type of object
for which it is called.
- A call to a non-virtual function is resolved according to the type of the pointer or
reference.
- If a function is declared virtual in the base class it is virtual in all derived classes
throghout the inhertance hierarchy.
- Virtual function must be member of some class
- Virtual function cannot be a static member function or a global function
- A virtual function that has been defined in a base class need not be defined in the
derived class. If it is not, the function defined for the base is called
- It is an error for a derived class function to differ from a base class virtual
function in the return type only.
- If return type is same and argument list differ, compiler allows this but late
binding is not happen.

Example:

#include <iostream>
using namespace std;

class Base // Base class


{
public:
virtual void f1() // Virtual member function.
{ cout << "Called Base::f1()\n"; }

virtual void f2() // Virtual member function.


{ cout << "Called Base::f2()\n"; }

};

class Derived : public Base // Derived class : public inheritance


{
public:

Page 47 of 78
Concepts in C++

void f1() // Implementation of virtual function - override


{ cout << "Called Derived::f1()\n"; }

void f3()
{ cout << "Called Derived::f3()\n"; }

};

int main()
{
Base *bp = new Derived;
bp->f1();
bp->f2();
// bp->f3(); // Error: Base::f3 not available

cout << "Size of Derived = " << sizeof(Derived) << endl;


return 0;
}

Result:
Called Derived::f1()
Called Base::f2()
Size of Derived = 4 (VPTR)

Mechanism of Virtual Function Call Æ


- Whenever there is one or more virtual function in a class the compiler secretly
places a virtual pointer VPTR in the class.
- The compiler secretly inserts code into the beginning of the constructor that
initializes the VPTR to point to proper VTABLE.
- When a virtual function call is made through a base class pointer (polymorphic
call) the compiler quietly inserts code to fetch the VPTR and look up the function
address in the VTABLE, thus calling the correct function and causing late binding
to take place.

Function Overriding Æ
- The redefinition of a virtual member function in a derived class with the same
signature is called function overriding

Pure virtual function and abstract class Æ

Page 48 of 78
Concepts in C++

- The use of one or more pure virtual function makes a class abstract, which
means that no object can be instantiated from it.
- When an abstract class is inherited, all the pure virtual functions must be
implemented, or the inherited class becomes abstract as well.

Syntax:
virtual void pure_virtual_func() = 0;

Object Slicing Æ
- Passing a derived object by value to a function that takes a base object by value
may cause a problem known as "object slicing"; every additional member
declared in the derived object is omitted. The resultant object contains only the
members declared in the base class.
- Dynamic binding mechanism is inoperative in this case.

Example:

#include <iostream>
using namespace std;

class Base
{
public:
virtual void f1() // virtual member function
{ cout << "Base::f1()" << endl; }

void f2() // non-virtual member function


{ cout << "Base::f2()" << endl; }
};

class Derived : public Base


{
public:
void f1() // overriding
{ cout << "Derived::f1()" << endl; }

void f2() // redefinition


{ cout << "Derived::f2()" << endl; }

void f3() // additional member function


{ cout << "Derived::f3()" << endl; }
};

void func1(Base b)
{
b.f1(); // No dynamic binding - calls Base:f1()
b.f2();
// b.f3(); // Error : f3 not available - sliced
}

void func2(Base *bp)


{

Page 49 of 78
Concepts in C++

bp->f1();
bp->f2();
// bp->f3(); // Error : f3 not available
}

int main()
{
Base b;
Derived d;

cout << "Size of Base = " << sizeof(b) << endl;


cout << "Size of Derived = " << sizeof(d) << endl;

func1(d);
func2(&d);

return 0;
}

Result:
Size of Base = 4
Size of Derived = 4
Base::f1()
Base::f2()
Derived::f1()
Base::f2()

Destructor of Base class should be virtual Æ


- If the destructor is not virtual then the deletion of a derived object through a
base class pointer will only delete the base part of the object.
- If the destructor is virtual then the derived class implementation of the destructor
is called first and then the base class destructor so that both parts of the derived
class object are destroyed properly.
- Whenever the class has at least one virtual function the destructor should be
made virtual. Having virtual functions indicate that a class is meant to act as an
interface to derived classes.

Example:

#include <iostream>
using namespace std;

class Base // Base class


{
public:
Base() // Constructor
{ cout << "Called Base::Base()\n"; }

virtual ~Base() // Destructor


{ cout << "Called Base::~Base()\n"; }

};

Page 50 of 78
Concepts in C++

class Derived : public Base // Derived class


{
public:
Derived() // Constructor
{ cout << "Called Derived::Derived()\n"; }

~Derived () // Destructor
{ cout << "Called Derived::~Derived()\n"; }
};

int main()
{
Base *bp = new Derived;
delete bp;

return 0;
}

Result:
Called Base::Base()
Called Derived::Derived()
Called Derived::~Derived()
Called Base::~Base()

Calling Member Functions and Virtual Functions within Constructor and


Destructor Æ
- If a virtual function is called inside a constructor, only the local version of the
function is called. That is, the virtual mechanism does not work within
constructor. As constructor of the base class is called before the constructor of
the derived class; virtual function within a constructor might manipulate
members that are not yet initialized.
- If a virtual function is called inside a destructor, only the local version of the
function is called. That is, the virtual mechanism does not work within
destructors. As destructor of the derived class is called before the destructor of
the base class; virtual function within a destructor might rely on portions of an
object which is already been destroyed.

Example:

#include <iostream>
using namespace std;

class Base // Base class


{
public:
Base() // Default constructor
{ cout << "Base::Base()\n";
f1();
f2();
}

Page 51 of 78
Concepts in C++

virtual ~Base() // destructor


{ cout << "Base::~Base()\n";
f1();
f2();
}

void f1() // member function


{ cout << "Base::f1()\n"; }

virtual void f2() // virtual member function


{ cout << "Base::f2()\n"; }

};

class Derived : public Base // Derived class


{
public:
Derived() // Default constructor
{ cout << "Derived::Derived()\n";
f1();
f2();
}

~Derived() // destructor
{ cout << "Derived::~Derived()\n";
f1();
f2();
}

void f1() // redefinition


{ cout << "Derived::f1()\n"; }

void f2() // overriding


{ cout << "Derived::f2()\n"; }
};

int main()
{
Base * bp = new Derived;
cout << "\nAfter construction\n\n";
delete bp;

return 0;
}

Result:
Base::Base()
Base::f1()
Base::f2()
Derived::Derived()
Derived::f1()
Derived::f2()

Page 52 of 78
Concepts in C++

After construction

Derived::~Derived()
Derived::f1()
Derived::f2()
Base::~Base()
Base::f1()
Base::f2()

Why not virtual constructor Æ


- Constructor of a base class is not inherited into the derived class.
- A virtual call is a mechanism to get work done given partial information. In
particular, "virtual" allows us to call a function knowing only an interfaces and not
the exact type of the object. To create an object you need complete information.
In particular, one needs to know the exact type of object to created.
Consequently, a "call to a constructor" cannot be virtual.
- When an object containing virtual functions is created, its VPTR must be
initialized to point to the proper VTABLE. Constructor is the function that
initializes an object and it initializes the VPTR too. The compiler secretly inserts
code into the beginning of the constructor that initializes the VPTR.

Factory pattern Æ
- Factory pattern is a technique for generating an object of an appropriate type
using an abstract class.

Example:

#include <iostream>
using namespace std;

class A
{
// …
};

class AX : public A
{
// …
};

class F // abstract class


{
public:
// interface to object creation functions – so called virtual constructor
virtual A* make_an_A() const = 0;
};

class FX : public F
{

Page 53 of 78
Concepts in C++

public:
A* make_an_A() const // override
{ return new AX(); }
};

void user(const F& f)


{
A* pA = f.make_an_A(); // make an A of the appropriate type
}

int main()
{
user(FX()); // this user makes AXs
return 0;
}

Page 54 of 78
Concepts in C++

9. Multiple Inheritance

Duplicate Subobjects and Ambiguous Upcasting Æ


- This happens in case of multiple inheritance when duplicate subobjects are there
in the multiply inherited class.

Example:

#include <iostream>
using namespace std;

class Base
{
int k;
public:
virtual char* vf() const = 0; // pure virtual function
virtual ~Base() {}
};

class D1 : public Base


{
public:
char* vf() const { return "D1"; }
};

class D2 : public Base


{
public:
char* vf() const { return "D2"; }
};

class MI : public D1, public D2 // multiple inheritance


{};

Page 55 of 78
Concepts in C++

int main()
{
Base* bp[3];

bp[0] = new D1;


bp[1] = new D2;
// bp[2] = new MI; // Error : ambiguous upcasting

for(int i = 0; i < 2; i++)


cout << bp[i]->vf() << endl;

for(int i = 0; i < 2; i++)


delete bp[i];

return 0;
}

Result:
D1
D2

Virtual Base Class Æ


- When the base class is inherited as virtual, only one subobject of that class will
ever appear as a base class.
- Virtual base classes are implemented by the compiler with pointer.

Example:

#include <iostream>
using namespace std;

class Base
{
int k;
public:
virtual char* vf() const = 0; // pure virtual function
virtual ~Base() {}
};

class VD1 : virtual public Base // virtual inheritance


{
public:
char* vf() const { return "VD1"; }
};

class VD2 : virtual public Base // virtual inheritance


{
public:
char* vf() const { return "VD2"; }
};

class VMI : public VD1, public VD2 // multiple inheritance

Page 56 of 78
Concepts in C++

{
public:
char* vf() const { return "VMI"; }
};

int main()
{
Base* bp[3];

bp[0] = new D1;


bp[1] = new D2;
bp[2] = new MI; // ok

for(int i = 0; i < 3; i++)


cout << bp[i]->vf() << endl;

for(int i = 0; i < 3; i++)


delete bp[i];

return 0;
}

Result:
VD1
VD2
VMI

Most Derived Class and Virtual Base Initialization Æ


- When a virtual base class is used, the most-derived constructor is responsible for
initializing that virtual base class. That means any class, no matter how far away
it is from the virtual base, is responsible for initializing it.
- The initialization of virtual base class in the most derived class may be avoided
by creating a default constructor for the virtual base class.

Overhead Æ
- The multiple inheritance mechanism is implemented using pointers
- The classes bear the extra overhead of pointers

Example:

#include <iostream>
using namespace std;

class Base
{
int k;
public:
virtual char* vf() const{};
virtual ~Base() {}
};

Page 57 of 78
Concepts in C++

class D1 : public Base


{
public:
char* vf() const { return "D1"; }
};

class D2 : public Base


{
public:
char* vf() const { return "D2"; }
};

class MI : public D1, public D2


{
public:
char* vf() const { return "MI"; }
};

class VD1 : virtual public Base // virtual inheritance


{
public:
char* vf() const { return "VD1"; }
};

class VD2 : virtual public Base // virtual inheritance


{
public:
char* vf() const { return "VD2"; }
};

class VMI : public VD1, public VD2 // multiple inheritance


{
public:
char* vf() const { return "VMI"; }
};

int main()
{
Base b;
D1 d1;
MI mi;
VD1 vd1;
VMI vmi;

cout << "size of b = " << sizeof(b) << endl;


cout << "size of d1 = " << sizeof(d1) << endl;
cout << "size of mi = " << sizeof(mi) << endl;
cout << "size of vd1 = " << sizeof(vd1) << endl;
cout << "size of vmi = " << sizeof(vmi) << endl;

Page 58 of 78
Concepts in C++

return 0;
}

Result:
size of b = 8 (int + VPTR)
size of d1 = 8 (int + VPTR)
size of mi = 16 (int + VPTR + int + VPTR)
size of vd1 = 12 (int + VPTR + Extra pointer)
size of vmi = 16 (int + VPTR + VPTR + Extra pointer)

Page 59 of 78
Concepts in C++

10. Dynamic Type Information and Casting

typeid Æ
- information about unknown object can be found with this operator

dynamic_cast Æ
- type of a class can be checked with this operator
- type safe downcasting is done with this
- pointer types can be changed with this operator

Example:

Base *bp;
Derived d;
Bp = &d;

dp = dynamic_cast<Derived *>(bp);

const_cast Æ
- this operator is used to explicitly override const/volatile in a cast

static_cast Æ
- performs a non polymorphic cast
- can be used for any standard conversion

reinterpret_cast Æ
- this converts one type into a fundamentally different type. eg. pointer into an
integer

Page 60 of 78
Concepts in C++

11. Templates

Advantages of templates Æ
- code reuse
- allows container classes (e.g. lists, arrays, etc.) to be simply defined without loss
of static type checking or run-time efficiency.
- allows definition of generic functions (e.g., sort) to be defined once for a family of
types

function template and template function Æ


- function templates are used to implement an entire range of related(overloaded)
functions
- when the actual parameter is substituted in the template the process is called
instantiating the function template and each instantiated version is called a
template function. i.e. template function is a specific instance of function
template.

class templates and template class Æ


- class templates are used to implement an entire range of related classes.
- Template class is the instantiation with the type argument

auto_ptr Æ
- Auto_ptr is a template class and is initialized with a pointer and can be
derefenced in the way a pointer can.
- Auto_ptr supports resource acquisition is initialization technique
- Auto_ptr has ownership semantics or destructive copy semantics – when an
auto_ptr is copied into another, the source no longer points to anything
- Copying a auto_ptr modifies it – a const auto_ptr cannot be copied.
- The purpose of the auto_ptr scheme is that dynamically allocated objects are
properly destroyed in all circumstances i.e. the object’s destructor is properly
executed.
- Template specification of auto_ptr:

template<class T>
class auto_ptr
{
public:
typedef T element_type;

explicit auto_ptr(T *p = 0) throw();

auto_ptr(const auto_ptr<T>& rhs) throw();


auto_ptr<T>& operator=(auto_ptr<T>& rhs) throw();

~auto_ptr();

T& operator*() const throw();


T *operator->() const throw();

Page 61 of 78
Concepts in C++

T *get() const throw();


T *release() const throw();
};

Example:

#include <iostream>
#include <memory>
using namespace std;

class X
{
public:
X() { cout << “X::X()\n” ;}
~X() { cout << “X::~X()\n” ;}
void f() { cout << “X::f()\n”; }
};

int main()
{
auto_ptr<X> p1(new X), p2;

p2 = p1; // ownership transfer


p2->f();

X *ptr = p2.get();
ptr ->f();

return 0;
}

Result:
X::X()
X::f()
X::f()
X::~X() (Destructor called when scope ends)

Page 62 of 78
Concepts in C++

12. Exceptions

Implemented using 3 keywords try, throw and catch Æ


- try block - Keyword try is prefixed to a block of statements which may generate
exception
- throw statement - when an exception is detected, it is thrown using throw
statement within the try block
- catch block - block defined by the keyword catch to catch the exception thrown
by the try block and handles it appropriately

Unwinding the stack Æ


- If a function terminates via an exception throw instead of via a return call, the
program frees memory from the stack. But instead of stopping at the first return
address on the stack, the program continues freeing stack until it reaches a
return address that resides in a try block. Control then passes to the exception
handlers at the end of the block rather to the first statement following the
function call. This process is called unwinding the stack.
- The throw operation calls the destructors for all the automatic objects
instantiated since entry to the try block.

Page 63 of 78
Concepts in C++

terminate, set_terminate, unexpected, set_unexpected Æ

Function Declaration Use

Install your own termination


typedef void
set_terminate routine to be called by
(*terminate_function)();
terminate

typedef void
(*unexpected_function)();
Install your own termination
set_unexpected function to be called by
unexpected_function
unexpected
set_unexpected(
unexpected_function unexp_func);
Called automatically under
void terminate(void); certain circumstances after
exception is thrown. The
terminate
terminate_function set_terminate( terminate function calls
terminate_function term_fun ); abort() or a function you
specify using set_terminate
Calls terminate() or a
unexpected void unexpected(void); function you specify using
set_unexpected.

- The terminate() function is called whenever the exception handling subsystem


fails to find a matching catch statement for an exception. It is also called when
the program attempts to rethrow an exception when no exception was originally
thrown. It may be called when an destructor throws an exception during
unwinding of stack
- By default terminate() calls abort()
- The unexpected() function is called when a function attempts to throw an
exception that is not allowed by its throw list.
- By default unexpected() calls terminate()

Page 64 of 78
Concepts in C++

Example:

#include <iostream>
#include <cstdlib>
#include <exception>
using namespace std;

void custom_handler()
{
cout << "Inside custom_handler" << endl;
abort();
}

int main()
{
cout << “main starts” << endl;
set_terminate(custom_handler); // set new terminate handler

try
{
cout << "Inside try block" << endl;
throw 100; // throw integer exception
}
catch (double i) // does not catch int exception
{
cout << "Inside catch" << endl;
}

cout << “main ends” << endl;


return 0;
}

Result:
main starts
Inside try block
Inside custom_handler
abnormal program termination

Page 65 of 78
Concepts in C++

Rethrow an exception Æ
- When an exception is rethrown, it is not re-caught by the same catch statement.
It propagates outwards to the next catch statement.

Example:

#include <iostream>
using namespace std;

void Xhandler()
{
try
{
throw "Hello";
}
catch (const char* str)
{
cout << "Caught " << str << " inside Xhandler” << endl;
throw; // rethrow exception
}
}

int main()
{
cout << "main starts" << endl;
try
{
Xhandler();
}
catch (const char* str)
{
cout << "Caught " << str << " inside main" << endl;
}

cout << "main ends" << endl;


return 0;
}

Result:
main starts
Caught Hello inside Xhandler
Caught Hello inside main
main ends

Page 66 of 78
Concepts in C++

13. Standard Template Library (STL)

Components of STL Æ
- Containers
- Iterators
- Algorithms
- Predicates or Function Objects
- Allocators

Containers Æ
- Container is an object that stores data in a certain way in memory
- Implemented using template classes and hence can hold any type of data
- classified in to 3 types
1. Sequence Containers (vector, list, deque)
2. Associative Containers (set, multiset, map, multimap)
3. Derived containers or container adapters (stack, queue, priority_queue)

Sequence Containers Æ

characteristics Features Iterators


Relocating, - quick random access by index Random
expandable array number access
- slow insert or delete in the
vector
middle
- constant time insert or delete at
the end
Doubly linked list - slow random access Bidirectional
list - constant time insert or delete at
any location
Like vector, but - quick random access by index Random
can be accessed at number access
either end - slow insert or delete in the
deque middle
- constant time insert or delete
(push and pop) at either
beginning or at the end

Associative Containers Æ

characteristics Features Iterators


Stores unique - stores only key objects Bidirectional
set sets - only one key of each value
allowed
Stores set with - stores only key objects Bidirectional
multiset duplicates - multiple key values allowed

Page 67 of 78
Concepts in C++

Stores unique - associates key object with value Bidirectional


one to one object
map
mapping of key - only one key of each value
value pairs allowed
Stores one to - associates key object with value Bidirectional
many mapping object
multimap
of key value - multiple key values allowed
pairs

Derived containers or container adapters Æ

characteristics Features Iterators


Can be - insert (push) and remove (pop) No Iterator
implemented as at one end only
stack
vector, list or
deque
Can be - insert (push) at one end and No Iterator
queue implemented as remove (pop) at other end
list or deque
Can be - insert (push) in random order at No Iterator
Priority
implemented as one end and remove (pop) in
_queue
vector or deque sorted order from other end

Member function common to all containers Æ

Function Name Description

returns an iterator to the start of the container, for iterating


begin()
forward through the container
returns an iterator to the past the end location of the container,
end()
used to end forward iteration
returns true if the container is empty
empty()
returns the number of items in the container
size()
returns the size of largest possible container
max_size()
returns a reverse iterator to the end of the container, for iterating
rbegin()
backward through the container
returns a reverse iterator to the beginning of the container, used
rend()
to end backward iteration
erase one or more items in a container
erase()
erase all the elements in a container
clear()

Iterators Æ

Page 68 of 78
Concepts in C++

- Iterator is a higher level abstraction of pointers


- Iterators behave like pointers that are used to access individual elements in a
container
- Iterators cannot be used to traverse derived containers

5 Iterator types and description Æ

Iterator Read/
Access Direction Description
Type Write
linear forward only R - Read an element.
- Move only one element at a
Input
time.
- Supports one-pass algorithms
linear forward only W - Write an element.
- Move only one element at a
output
time.
- Supports one-pass algorithms
linear forward only RW - Have the capabilities of input &
forward output iterators.
- Can retain the current state
linear forward & RW - Has forward iteration capability
back and can move in both
bidirectional
directions.
- Supports Multi-pass algorithms
random forward & RW - Has bi-directional capability
random back and can access any element &
access move arbitrary no. of elements

Algorithms Æ
- operate on containers
- can be applied on ordinary C++ arrays

Important Algorithms Æ

Algorithm Description

looks for the first element in a container that has a specified value
find()
counts the number of elements in acontainer having a specified
count()
value and returns this number
sorts the elements in a container
sort()
looks for a sequence of values , specified by one container, within
search()
another container
works on three containers, merging the elements from two source
merge()
containers into a destination container

Page 69 of 78
Concepts in C++

does something to every item in the container


for_each()
does something to every item in a container, and places the
transform()
resulting values in a different container (or the same one)

Predicates or Function Objects Æ


- The function objects are used as arguments to certain containers and algorithms
- function object is object of a class that overloads operator () and is the only
member function and has no data
- Algorithms use function objects as callback functions and are invoked for each
object it processes from the container
- A function object can also process the objects that algorithm finds and returns an
object of the type in the container
- Since the function call operator is overloaded in function objects, they can be
passed to objects at compile time and increase the efficiency by inlining the
corresponding call.
- Predicates assure that program uses generic algorithms in all situations.

Example:

#include <iostream>
#include <vector>
using namespace std;
#include <algo.h>

class multiply
{
public:
int operator()(int x, int y) // overloaded () operator
{ return x*y; }
};

int main()
{
int x[5] = {1, 2, 3, 4, 5};
vector<int> v1(x, x+5); // initialize vector

int product = accumulate( v1.begin(), v1.end(), 1, multiply() );


cout << "product = " << product << endl;

return 0;
}

Result:
product = 120

Allocators Æ
- Every STL container class defines an allocator class that manages the allocation
of memory for the container.
- STL provides default allocator object for each container types so that
programmers need not deal with it directly.

Page 70 of 78
Concepts in C++

- STL uses this allocator for storage allocation instead of using new and delete
- Programmers can supply allocator to customize how a container handles storage
management

Page 71 of 78
Concepts in C++

14. Object Oriented Design Basics

ISA Relationship Æ
- A specialized class "is" a specialization of another class and, therefore, has the
ISA relationship with the other class.
- This relationship is best implemented by
• deriving one class from another - inheritance

Example:
An Employee ISA Person. Employee is derived from Person.

HASA Relationship Æ
- A class may have an instance of another class.
- This relationship can be implemented in two ways:
• Embedding one class object in another - composition
• Having one class as an inner class of the other – inner class

Example:
An employee "has" a salary, therefore the Employee class has the HASA relationship
with the Salary class. This relationship is best implemented by embedding an object
of the Salary class in the Employee class.

15. Anonymous

Anonymous Unions
Anonymous unions are unions that are declared without a class-name or declarator-
list.

Syntax

union { member-list } ;

Such union declarations do not declare types — they declare objects. The names
declared in an anonymous union cannot conflict with other names declared in the
same scope.

Names declared in an anonymous union are used directly, like nonmember variables.
The following example illustrates this:
#include <iostream.h>

struct DataForm
{
enum DataType { CharData = 1, IntData, StringData };
DataType type;

// Declare an anonymous union.


union
{

Page 72 of 78
Concepts in C++

char chCharMem;
char *szStrMem;
int iIntMem;
};
void print();
};

void DataForm::print()
{
// Based on the type of the data, print the
// appropriate data type.
switch( type )
{
case CharData:
cout << chCharMem;
break;
case IntData:
cout << szStrMem;
break;
case StringData:
cout << iIntMem;
break;
}
}
In the function DataForm::print, the three members (chCharMem, szStrMem, and
iIntMem) are accessed as though they were declared as members (without the
union declaration). However, the three union members share the same memory.

In addition to the restrictions listed in Union Member Data, anonymous unions are
subject to additional restrictions:

• They must also be declared as static if declared in file scope.

• They can have only public members; private and protected members in
anonymous unions generate errors.

• They cannot have function members.

Note Simply omitting the class-name portion of the syntax does not make a union
an anonymous union. For a union to qualify as an anonymous union, the declaration
must not declare an object.

Anonymous Structures

Anonymous structures can be useful when the tag named is not needed. This is the
case when one declaration defines all structure instances. For example:
struct
{
int x;
int y;

Page 73 of 78
Concepts in C++

} mystruct;
Embedded structures are often anonymous.
struct somestruct
{
struct /* Anonymous structure */
{
int x, y;
} point;
int type;
} w;

Anonymous Class Types


Classes can be anonymous — that is, they can be declared without an identifier.
Anonymous classes are subject to certain restrictions. (For more information about
anonymous unions, see Unions.) Anonymous classes:

• Cannot have a constructor or destructor.

• Cannot be passed as arguments to functions (unless type checking is


defeated using ellipses).

• Cannot be returned as return values from functions.


Class
{
Public:
Int z;
Int x;
}fun;

static_cast
A static_cast is used for all conversions that are well-defined. These include
“safe” conversions that the compiler would allow you to do without a cast and
less-safe conversions that are nonetheless well-defined. The types of
conversions covered by static_cast include typical castless conversions,
narrowing (information-losing) conversions, forcing a conversion from a void*,
implicit type conversions, and static navigation of class hierarchies:
//: C24:Statcast.cpp
// Examples of static_cast

class Base { /* ... */ };


class Derived : public Base {
public:
// ...
// Automatic type conversion:
operator int() { return 1; }
};

Page 74 of 78
Concepts in C++

void func(int) {}

class Other {};

int main() {
int i = 0x7fff; // Max pos value = 32767
long l;
float f;
// (1) typical castless conversions:
l = i;
f = i;
// Also works:
l = static_cast<long>(i);
f = static_cast<float>(i);

// (2) narrowing conversions:


i = l; // May lose digits
i = f; // May lose info
// Says "I know," eliminates warnings:
i = static_cast<int>(l);
i = static_cast<int>(f);
char c = static_cast<char>(i);

// (3) forcing a conversion from void* :


void* vp = &i;
// Old way produces a dangerous conversion:
float* fp = (float*)vp;
// The new way is equally dangerous:
fp = static_cast<float*>(vp);

// (4) implicit type conversions, normally


// Performed by the compiler:
Derived d;
Base* bp = &d; // Upcast: normal and OK
bp = static_cast<Base*>(&d); // More explicit
int x = d; // Automatic type conversion
x = static_cast<int>(d); // More explicit
func(d); // Automatic type conversion
func(static_cast<int>(d)); // More explicit

// (5) Static Navigation of class hierarchies:


Derived* dp = static_cast<Derived*>(bp);
// ONLY an efficiency hack. dynamic_cast is
// Always safer. However:
// Other* op = static_cast<Other*>(bp);

Page 75 of 78
Concepts in C++

// Conveniently gives an error message, while


Other* op2 = (Other*)bp;
// Does not.
} ///:~
In Section (1), you see the kinds of conversions you’re used to doing in C, with or
without a cast. Promoting from an int to a long or float is not a problem because
the latter can always hold every value that an int can contain. Although it’s
unnecessary, you can use static_cast to highlight these promotions.
Converting back the other way is shown in (2). Here, you can lose data because
an int is not as “wide” as a long or a float – it won’t hold numbers of the same
size. Thus these are called “narrowing conversions.” The compiler will still
perform these, but will often give you a warning. You can eliminate this warning
and indicate that you really did mean it using a cast.
Assigning from a void* is not allowed without a cast in C++ (unlike C), as seen in
(3). This is dangerous and requires that a programmer know what he’s doing.
The static_cast, at least, is easier to locate than the old standard cast when
you’re hunting for bugs.
Section (4) shows the kinds of implicit type conversions that are normally
performed automatically by the compiler. These are automatic and require no
casting, but again static_cast highlights the action in case you want to make it
clear what’s happening or hunt for it later.
If a class hierarchy has no virtual functions or if you have other information that
allows you to safely downcast, it’s slightly faster to do the downcast statically
than with dynamic_cast, as shown in (5). In addition, static_cast won’t allow
you to cast out of the hierarchy, as the traditional cast will, so it’s safer. However,
statically navigating class hierarchies is always risky and you should use
dynamic_cast unless you have a special situation.
const_cast
If you want to convert from a const to a non const or from a volatile to a non
volatile, you use const_cast. This is the only conversion allowed with
const_cast; if any other conversion is involved it must be done separately or
you’ll get a compile-time error.
//: C24:Constcst.cpp
// Const casts

int main() {
const int i = 0;
int* j = (int*)&i; // Deprecated form
j = const_cast<int*>(&i); // Preferred
// Can't do simultaneous additional casting:
//! long* l = const_cast<long*>(&i); // Error
volatile int k = 0;
int* u = const_cast<int*>(&k);
}

class X {

Page 76 of 78
Concepts in C++

int i;
// mutable int i; // A better approach
public:
void f() const {
// Casting away const-ness:
(const_cast<X*>(this))->i = 1;
}
}; ///:~
If you take the address of a const object, you produce a pointer to a const, and
this cannot be assigned to a non const pointer without a cast. The old-style cast
will accomplish this, but the const_cast is the appropriate one to use. The same
holds true for volatile.
If you want to change a class member inside a const member function, the
traditional approach is to cast away constness by saying (X*)this. You can still
cast away constness using the better const_cast, but a superior approach is to
make that particular data member mutable, so it’s clear in the class definition,
and not hidden away in the member function definitions, that the member may
change in a const member function.

Questions:

1) What is virtual function?


A) you know it.
2) What is virtual destructor?
A) U know
3) What are the default functions of a class provided by compiler in c++?
A) Const, copy const, dest, assign oper
4) What is copy constructor and what are problem with the default copy
constructor provided by compiler
A) shallow copy is done in compiler provided copy const. Both pointesrs to
objects will point to the same object . Deletion of one would make the
another dangling.
5) How can you avoid overhead of deep copy in copy constructor ?
A) to maintain the reference count to the pointers to the objects. Static
refenrence count to have the count of obectes copied/created.
6) What is multiple inheritace?
A) U know.
7) What are the common problem in multiple inheritace? How to solve those ?
A) virtual base class concept.
8) What is virtual base class?
A) U know it.
9) What is abstract class?
A) U know it.
10) What code is reused in client server model implemented by abstract class?
A) client side code.
11) What is singleton class?
12) Is singleton class thread safe ? IF YES THEn why and if no then how to make
it.

Page 77 of 78
Concepts in C++

A) not thread safe. Use mutex lock before creating the objects.
13) What is design a pattern?
A)
14) What are different types of design pattern ?
A)
15) What is a visitor design pattern ?
A)
16) How many argument can be passed to a c-function as per ANSI standard ?
A) 253
17) Why do you pass arguments by reference in copy constructor? And what
happen if it is passed by value?
A) by value, it will be out of memory because of infinite loop. But in case of
reference, no copy constructor is being called.
18) In what all scenarios copy constructor is being called ?
A) retun statement, passing argument.
19) What is a private inheritace ? and why it is used ?
A) All the public and protected members become private in derived class.
B) To avoid the bottom to top casting.
20) How to overload ++A and A++ operated in user defined data type and how
compiler distinguish it ?
A) in A++ overloading you will pass an argument….you may refer some study
material….
21) What s/f life cycle you have used?????
22) what are different life cycles and their advantages….

Page 78 of 78

Вам также может понравиться