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

Write a program to perform the deletion of white spaces such as horizontal tab, vertical tab, spaces and new

line from a text file & to store the contents of the file without white spaces on other file.
Answer
One way to get input into a program or to display output from a program is to use
standard input and standard output, respectively. All that means is that to read in data,we use cin (or a few other
functions) and to write out data, we use cout.
When we need to take input from a file (instead of having the user type data at the
keyboard) we can use input redirection:

C++ File I/O


C++ has a general mechanism for reading and writing files, which is more flexible:-
iostream.h and fstream.h
There are types and functions in the library iostream.h that are used for standard I/O. fstream.h includes the
definitions for stream classes ifstream (for input from a file), ofstream (for output to a file) and fstream (for input
to and output from a file). Make sure you always include that header when you use files.
Type
For files you want to read or write, you need a file stream object, e.g.:
ifstream inFile; // object for reading from a file
ofstream outFile; // object for writing to a file
Functions
Reading from or writing to a file in C++ requires 3 basic steps:
Open the file.
Do all the reading or writing.
Close the file.
Following are described the functions needed to accomplish each step.
Opening a file:
In order to open a file, use the member function open(). Use it as:
inFile.open(filename, mode);
outFile.open(filename, mode);

#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<fstream.h>
void main()
{
char ch;
ifstream infile("f1.txt"); //opening of file1
clrscr();
ofstream outfile("f2.txt"); //opening of file2
while(infile) //while(infile !=EOF)
{
infile.get(ch); //reading character one by one
if(ch!=32 && ch!='\t' && ch!='\n') //checking if the read character is
not equal to ‘\t’=horizontal tab, 32=white spaces and ‘\n’=new line)
outfile.put(ch); //writing the character into another file
}
infile.close(); //after the operation closing the file1
outfile.close();//after the operation closing the file2
getch();
}

Classes Objects
Classes are static entities. Objects are dynamic/runtime entities.

1
A class can have many objects. Objects pertain to a single class.

Class is a template of an object. Object is an instance of the class.


Class is a logical construct. Object is a physical entity.

Classes are created using the keyword class. Objects are created using the class name.

Classes cannot interact without objects. Objects interact by sending messages to one another.

Syntax: class class_name Syntax: class_name object_name

Eg: class shape Eg: shape circle;

Overloaded functions Function templates


Function overloading allows the definition of more than one Template functions are a means of specifying to the compiler
function with the same name and provides a means of how to create new functions based on the instantiation type.
choosing between the functions by matching parameters.

Function overloading does not remove the overhead of Function templates remove the overhead of rewriting the same
rewriting the same functions. functions.

Overloading functions should be exact match of its prototype. Function templates do not follow such rule.

When the compiler encounters a call to such functions then When the compiler encounters a call to such functions then it
they are executed directly. recreates a copy of the function template internally.

The actual data type is passed at the time of function call. The actual data type is passed when the copy is created
internally and then the copy is executed.

The compiler will prefer to call this fn first as compared to The compiler will prefer to call this second first as compared
template. to overloaded function.

Call by value Call by reference


The values are passed through the arguments. The address is passed through the arguments.

Changes made to the parameters have no effect in the value Changes made to the parameters can affect the value.

By default the values are passed by call by value. Call by reference is not default.
Code within a function cannot alter the arguments used to call Code within a function can alter the arguments used to call the
the function. function.
The actual value is passed. The copy of the value is passed.
Parameters are declared as int, double, char etc. Parameters are declared as pointer types.
Parameters are accessed using the address of arguments. Parameters are accessed directly.
Syntax: Syntax:
Returntype functionname( arg ) Returntype functionname( * arg )
Eg:int sqr(int x) Eg:void swap(int *x, int *y);

b) How are values of fundamental data types converted to class objects? Give an example. (8)
Answer:
Assignment of data items are handled by the compiler with no effort on the part of the user, whether they are basic
or user defined provided both source and destination data items are of the same data-type.
In case the data-items are of different types, data conversion interface function must be explicitly specified by the
user.

2
These include conversions between basic and user-defined data-types of different types.
The compiler supports data conversion of only built-in data types supported by the language.
The user cannot rely on the compiler to perform the conversion from fundamental data-types to the user-defined
data-types, because the compiler does not know anything about the logical meaning of user defined data-types.
Therefore, to perform meaningful conversion, the user must supply the necessary conversion function.
To convert data from a fundamental data-type to a user-defined data-type, the conversion function should be defined
in the user-defined object’s class in the form of a constructor.
This constructor function takes a single argument of fundamental data-type as shown below:
Constructor of the
class Fundamental data
Constructor (BasicType)
{
type
//steps for converting
//Fundamental Type to Object attributes
} Example:
class Meter
{
private:
int met;
public:
Meter()
{ met=0;}
Meter(int m)
{ met=m;}
void showMeter()
{ cout<<met;}
operator int()
{ return met;}
};
void main()
{
int x=16;
Meter m1=x;
m1.showMeter();
Meter m2=20;
x=m2;
cout << x << endl;
m2.showMeter();
}
The statements such as :
Meter m2=20;
x=m2;

invokes the same conversion function.


The only difference is, in the case of the first statement, the conversion function is invoked as a part of object
creation activity, whereas in the case of the second statement, the compiler first searches for the overloaded
assignment operator function, and if that is not found, it invokes the one argument constructor.

The distinction between the function definition and the assignment operator overloading for type conversion is
blurred by the compiler; the compiler looks for a constructor if an overloaded = operator function is not available to
perform the data conversion.

a) If delete operator is applied to a base class pointer, the base class deconstructor is called even if the pointer
points to an instance of a derived class. What change should be done so that appropriate deconstuctor is
called? Explain with suitable example. (12)
Answer:
3
Destructor:
A destructor is a member function of a class, which is called when an object of that class goes out of scope.
This means all clean up operation and final steps of the object’s destruction are to be done by the destructor
function.
A difference between a destructor (and the constructor) and other member functions is that, if a regular member
function has a body in the derived class, only the version of the Derived class gets executed.
Whereas in case of destructors, both derived as well as base class versions get executed.
The order of execution of destructor in an inherited class during a cleanup is as follows:
Derived class destructor
Base class destructor
Applying delete operator to base class pointer:
If delete operator is applied to a base class pointer, the base class destructor is called even if the pointer points to an
instance of a derived class.
Hence, although the delete operator was intended for the derived class destructor to be called as well, only the base
class destructor is called.
Solution: Virtual Destructors:
If the class contains one or more virtual functions, the base class destructor should be declared virtual.
This makes all derived class destructors virtual, even though they do not have the same name as the base class
destructor.
In case a base class pointer is pointing to a dynamic derived class object, and when such memory is explicitly freed
using delete operator, then instead of invoking all the necessary derived class destructors in the hierarchy, it invokes
only the base class destructor, thereby possibly causing some undesirable side effects.
Simply by making the base class destructor virtual, the destructors for the appropriate derived classes down in the
hierarchy are also implicitly called.
We cannot however declare a pure virtual destructor.
Even if a virtual destructor is declared as pure, it will have to implement an empty body (at least) for the destructor.
Example:
#include<iostream.h>
class Shape
{
public:
Shape()
{cout<<”\nConstructing Shape”<<endl;}
virtual void draw()=0;
~Shape() //destructor not virtual
{ cout<<”\nDestructing Shape”<<endl;}
};
Q3 a) What are smart pointers? How are they created? (10)
// Write about iterators from the STL using an example
Write a program to print the truth table for Boolean expression AB + BC. The table will have only
entries 0 or 1.(10)
Answer:
#include<iostream.h>
#include<conio.h>
class Booleanop
{
private:
int arr[8];
public:
void populate();
void print();
Booleanop operator *(Booleanop);
Booleanop operator +(Booleanop);
};
void Booleanop::populate()
{
4
cout<<"\n\nEnter the values for the boolean array";
for(int i=0;i<8;i++)
cin>>arr[i];
}
void Booleanop::print()
{
cout<<endl;
for(int i=0;i<8;i++)
cout<<arr[i]<<" ";
}
Booleanop Booleanop::operator * (Booleanop temp1)
{
Booleanop temp;
for(int i=0;i<8;i++)
{
if(arr[i]==1 && temp1.arr[i]==1)
temp.arr[i]=1;
else if(arr[i]==0 && temp1.arr[i]==1)
temp.arr[i]=0;
else if(arr[i]==1 && temp1.arr[i]==0)
temp.arr[i]=0;
else if(arr[i]==0 && temp1.arr[i]==0)
temp.arr[i]=0;
else
cout<<"Value in array is neither 1 nor 0";
}
return temp;
}
Booleanop Booleanop::operator + (Booleanop temp1)
{
Booleanop temp;
for(int i=0;i<8;i++)
{
if(arr[i]==1 && temp1.arr[i]==1)
temp.arr[i]=1;
else if(arr[i]==0 && temp1.arr[i]==1)
temp.arr[i]=1;
else if(arr[i]==1 && temp1.arr[i]==0)
temp.arr[i]=1;
else if(arr[i]==0 && temp1.arr[i]==0)
temp.arr[i]=0;
else
cout<<"Value in array is neither 1 nor 0";
}
return temp;
}
void main()
{
Booleanop a,b,c,d,e,f;
clrscr();
a.populate();
b.populate();
c.populate();
cout<<"\n\n\nArray a is: ";
a.print();
cout<<"\n\nArray b is: ";
5
b.print();
cout<<"\n\nArray c is: ";
c.print();
d=a*b;
cout<<"\n\n(a.b) is: ";
d.print();
e=b*c;
cout<<"\n\n(b.c) is: ";
e.print();

=d+e;
cout<<"\n\n(a.b) + (b.c) is: ";
f.print();

getch();
}

Why is the difference between macro and inline function? Which one is preferred & why? (10)
Answer:
Inline function is a function provided by C++.It is declared by using the keyword inline before the function
prototype.
Macro is a a preprocessor directive provided by C. It is declared by using the preprocessor directive #define before
the actual statement.
Inlines are parsed by the compiler.
Macros are expanded by the preprocessor at pre-compile time.
Inline functions follow all the protocols of type safety enforced on normal functions like,
Argument types are checked, and necessary conversions are performed correctly & the compiler performs return
type checking, function signature before putting inline function into symbol table. They can be overloaded to
perform the right kind of operation for the right kind of data.
Macro have No such thing, hence, macros are more error prone as compared to inline functions. the The parameters
are not typed (the macro works for any objects of arithmetic type).
No error checking is done during compilation.
Eg. you can pass strings to a macro that does some integer arithmetic
#define MAX(a, b) ((a < b) ? b : a)
int main( void)
{
cout << "Maximum of 10 and 20 is " << MAX("20", "10") << endl;
return 0;
}
Inline member functions can access the class’s member data.
The preprocessor has no permission to access member data of a class and are thus useless even if used within a
class. Thus they can’t even be used as member functions.
Compiler performs return type checking function signature before putting inline function into symbol table.
But there is no type checking for Macros. So Macros are more error prone as compared to inline functions.
A macro is a constant that provides straight textual substitution where used, while an inline function is a procedure
that is actually called each time.
Debugging information for inlined code is usually more helpful than that of macro-expanded code.
Inline can be used for debugging a program as they are expanded at compile time and a break point can be placed at
the inline function definition and step into the method for debugging step by step.
Macro can’t be used for debugging as they are expanded at pre-compile time.
Inline functions may or may not be expanded by the compiler. It is the compiler’s decision whether to expand the
function inline or not.
Macros are always expanded.
Inline can be defined inside or outside the class.
Macro can not be defined inside the class.

6
Many constructs are awkward or impossible to express using macros, or use a significantly different syntax.
Inline functions use the same syntax as ordinary functions, and can be inlined and un-inlined at will with ease.
Inline functions pass arguments by value, just like regular functions do.
Expressions passed into macros are not always evaluated before entering the macro body and it don’t pass by value.
Since type checking can be used in inline functions, theirs problem can be avoided. Expressions may expand inside
the macro so that their evaluation precedence is different from what you expect.
So that inline is more preferable than Macro…

b) When is memory allocated & dealloacted in dynamic memory allocation during complied time, link time
and run time. (8)
Answer:
Compile Time:
Compile time refers to either the operations performed by a compiler, programming language requirements that
must be met by source code for it to be successfully compiled, or properties of the program that can be reasoned
about at compile time.
The operations performed at compile time usually include syntax analysis, various kinds of semantic analysis (e.g.,
type checks and instantiation of template) and code generation.
Programming language definitions usually specify compile-time requirements that source code must meet to be
successfully compiled. For example, the amount of storage required by types and variable can be deduced.
Properties of a program that can be reasoned about at compile time include range-checks (eg, proving that an array
index will not exceed the array bound), deadlock freedom in concurrent languages, or timings (eg, proving that a
sequence of code takes no more than an allocated amount of time).
Compile time occurs before link time and runtime.
Link Time:
Link time refers to either the operations performed by a linker or programming language requirements that must be
met by compiled source code for it to be successfully linked.
The operations performed at link time usually include fixing up the addresses of externally referenced objects and
functions, various kinds of cross module checks (eg, type checks on externally visible identifiers and in some
languages instantiation of template).
Some optimizing compilers delay code generation until link time because it is here that information about a
complete program is available to them.
The definition of a programming language may specify link time requirements that source code must meet to be
successfully compiled (eg, the maximum number of characters in an externally visible identifier that must be
considered significant).
Link time occurs after compile time and before runtime.
Run Time:
Run time or execution time refers most literally to the time during which a program is running (executing).
A "run-time error" is detected after or during the installation or copying of the program, whereas a "compile-time
error" is detected by the compiler before the program is so installed and started.
Type checking, storage allocation, and even code generation and code optimization may be done at compile-time or
upon a run-time, depending on the language and compiler.
Static Memory Allocation:
Basically, you should use static memory allocation when you know in advance how much memory is needed.
In this way the memory is allocated once and released upon exit.
With static allocation all the memory needed is known at compile time
Dynamic Memory Allocation:
In computer science, dynamic memory allocation (also known as heap-based memory allocation) is the allocation of
memory storage for use in a computer program during the runtime of that program.
It can be seen also as a way of distributing ownership of limited memory resources among many pieces of data and
code.
Dynamically allocated memory exists until it is released either explicitly by the programmer, or by the garbage
collector.
This is in contrast to static memory allocation, which has a fixed duration.
It is said that an object so allocated has a dynamic lifetime.
Dynamic Memory Allocation is used:

7
When you anticipate growth in your data structures, where you may only know the maximum needed memory, but
actual usage may be far less than that
When the number of objects that will be in use during runtime is not known at compile time.
When the memory space being used needs to be released once the program lifetime expires.
When you need for the data to persist throughout the process's lifetime but you don't want to use global memory for
the purpose.
Dynamic Memory Allocation during Runtime:
C++ provides two dynamic allocation operators: new and delete. These operators are used to allocate and
free memory at runtime.
The new operator:
The new operator allocates memory and returns a pointer to the start of it.
new attempts to allocate enough memory on the heap for the new data and, if successful, returns the address to the
newly allocated memory.
However if new cannot allocate memory on the heap it will throw an exception of type std::bad_alloc. This removes
the need to explicitly check the result of an allocation.
Syntax:
p_var = new typename;
where p_var is a previously declared pointer of type typename. typename can be any basic data
type or user-defined object (enum, class, and struct included). If typename is of class type, the default
constructor is called to construct the object.

To initialize a new variable created via new, the following syntax is used:
p_var = new type(initializer);
where initializer is the initial value assigned to the new variable, or if type is of class type, initializer is the
argument(s) to a constructor.
new can also create an array:
p_var = new type [size];
In this case, size specifies the length of one-dimensional array to create. The address of the first
element is returned and stored into p_var, so p_var[n-1] gives the value of the nth element (counting from 0)
The delete operator:
The delete operator frees memory previously allocated using new.
It must be used only with a valid pointer previously allocated by using new.
Memory allocated with new must be deallocated with delete to avoid a memory leak.
Arrays allocated with new[] must be deallocated with delete[].
Program:
#include<iostream.h>
#include<conio.h>
void main
{
int x,n,*a;
cout<<”\nEnter number of students: ”;
cin>>n;
a=new int [n]; //dynamicallocation
assert(a);
for(x=0;x<n;x++)
{
cout<<”\nEnter marks for student ”<<x+1<<” : ”;
cin>>a[x];
}
for(x=0;x<n;x++)
{
cout<<”\nEnter marks for student ”<<x+1<<” : ”<<a[x];
}
delete []a; //freeing memory
}

8
Explain exception handling. Give suitable example.
Exception handling:
The increase in complexity and size of the software systems have been accomplished by an increase in the costs
associated with their failure. The rising cost of failure in a computer system has stimulated interest in improving
software reliability.
The two main techniques for building reliable software are fault avoidance and fault tolerance. Fault tolerance deals
with the method of providing services complying with the specification in spite of faults having occurred by
redundancy.
Fault tolerance approach attempts to increase reliability by designing the system to continue to provide service in
spite of the presence of faults. In C++ , exception handling allows to build fault tolerant systems.
It begins with error detection. It must be possible to detect the occurrence of a latent error before nit leads to failure.
Once an error has been detected, the goal is error recovery.
The goal of fault tolerant design is to improve dependability by enabling the system to perform its intended function
in the presence of a given number of faults.
Keywords of exception handling- try, throw and catch:
C++ exception handling is built upon three keywords: “try”, “throw” & “catch”.
In the most general terms, program statements that you want to monitor for exceptions are contained in a “try”
block.
If an exception i.e. an error occurs within the try block, it is thrown using throw. The exception is caught using catch
and processed.
Any statement that throws an exception must have been executed from within a try block. A function called from
within a try block can also throw an exception.
Any exception must be caught by a catch statement that immediately follows the try statement that throws the
exception.
The general form of try and catch:
Try
{
……………………..
….try block…….
……………………..
}
Catch(type 1 arg)
{
……………………..
….catch block…….
……………………..
}
Catch(type 2 arg)
{
……………………..
….catch block…….
……………………..
}
The try block must contain the portion of your program that you want to monitor for errors.
Exceptions in C++:
The integer exception will not be caught by a double catch statement.
If you throw an exception for which there is no applicable catch statement, an abnormal program termination will
occur.
An unhandled exception causes the standard library function, terminate() to be invoked.
By default, terminate() calss abort() to stop your program.
The ‘bad_alloc’ class:
Standard C++ contains several built in exception classes. The most commonly used is probably ‘bad_alloc’, which is
thrown if an error occurs attempting to allocate memory with ‘new’.
Put all statements that use ‘new’ in a ‘try’ block. The catch block that follows, handles the exception, often by
displaying an error message and terminating the program.
Sequence od events when an exception occurs:
9
Code is executing normally outside a try block.
Control enters the try block.
A statement in the try block causes an error in a member function.
The member function throws an exception.
Control transfers to the exception handler (catch block) following the try block.

Write a program to read two integers from the keyboard and to perform simple arithematic operatrions
using the pointer technique. The memory space for the variables are allocated by the new pointer.
#include<iostream.h>
#include<conio.h>
class Arithematic
{
private: int *num1;
int *num2;
public:
Arithematic(int,int);
int addValue();
};
Arithematic:: Arithematic(int n1,int n2)
{
num1=new int;
num2=new int;
*num1=n1;
*num2=n2;
cout<<"\n\tObject Created:"<<*num1<<"\t"<<*num2;
}
int Arithematic::addValue()
{
return(*num1+*num2);
}
void main()
{
clrscr();
Arithematic A3(2,4);
int s=A3.addValue();
cout<<"\n\tAddition is:"<<s;
}

Q.Containership & inheritance difference??


The other way of inheriting properties of one class into another is called containership or containment or nesting or
composition or embedded class.
This approach takes a view that an object can be a collection of many other objects. That is, a class can contain
objects of other classes as its data members.
A containership supports a “has a” relationship. Hence, In object oriented programming the “has a” relationship
occurs when one object is contained in another.
A real-world example of composition may be seen in an automobile: the objects wheel, steering wheel, seat, gearbox
and engine may have no functionality by themselves, but an object called automobile containing all of those objects
would serve a higher function, greater than the sum of its parts.
The declaration could be:
class Alpha
{
…….
};
class Beta
{
……
10
};
class Gamma
{
Alpha a;
Beta b;
};
Here, All objects of gamma class will contain the objects a and b;
Creation of a nested object is different from that of independent object. An independent object is created by its
constructor when it is declared with arguments. On the other hand, a nested object is created in two stages. First, the
member objects are created using their respective constructors, and then other ordinary members are created.
We can have as many member objects as are required in a class.
The constructors of the member objects are called in the order in which they are declared in the nested class.
The containership is different from inheritance in many aspects:
An Inheritance supports “is a“ relationship, unlike of containership which supports “has a” relationship.
In containership, A class contains object of another class as a data member. Whereas in Inheritance, A derived class
that inherits from the base class is a specialized form of the base class, i.e. it has all the characteristics of the base
class as well as some of its own.
The declaration of inheritance could be:
class Beta
{
…. …. ….
};
class Alpha : public Beta
{
…. …. ….
};

The Declaration of containership could be:


class Beta
{
…. …. ….
};
class Alpha
{
Beta b;
};
#############################
void main()
{
int i, gd=DETECT, gm;
initgraph(&gd, &gm, "c:\\tc\\bgi");

shape * pshape[2];
pshape[0]=new ball(40,12,5,BLUE,4);
pshape[1]=new rect(12,7,10,15,RED,1);

pshape[0]->draw();
pshape[1]->draw();

getch();
closegraph();
}
########################
#include<iostream.h>
#include<conio.h>
#include<process.h>
11
class safearray
{
private:
int arr[5];
public:
int& operator [](int n) //Note return type is by reference
{
if(n<0 || n>4)
{
cout<<"\n index out of bounds ";
getch();
exit(1);
}
return(arr[n]);
}
};
void main()
{
safearray ob1;
clrscr();
int i;
for(i=0;i<5;i++) //To fill the array with data
{
ob1[i] = i*10;/* Overloaded subscript [] operator is called here.The compiler will read it as: Ob1.operator[](i)
and if within bounds will return address of the I th element of the array, into which the value i*10 will be stored.*/
}
for(i=0;i<5;i++) //Display of data
{
cout<<ob1[i]<<"\t";
}
cout<<endl;
getch();
}
------------Output-------------
0 10 20 30 40
-----------output--------------
index out of bounds

DYNAMIC CAST AND STATIC CAST:


Dynamic cast:
Although c++ still fully support the traditional casting operator defined by the c,c++ adds four new ones.
They are dynamic_cast,const_cast,reinterpret_cast,static_cast.
The dynamic_cast operator performs a run-time cast that verifies the validity of a cast. If, at the time dynamic_cast
is executed, the cast is invalid,the cast is fails. The general form of dynamic_cast is:
Dynamic_cast<target_type>(expr)
Here target type specifies the target type of cast and expr is the expression being cast into the new type. The target
type must be a pointer or reference type, and the expression being cast must evaluate to a pointer or a
reference.Thus,dynamic cast can be used to cast one type of pointer into another or one type of reference into
another.
The purpose of dynamic_cast is to perform casts on polymorphic types. For eg,given the two polymorphic classes
B and D,with D derived from B,a dynamic_cast can always cast a D* pointer into a B* pointer. This is because a
base pointer is always point to a derived object.
But a dynamic_cast pointer can cast a B* pointer into an D* pointer only if the object being pointed to actually is a
D object. In a general,dynamic_cast will succeed if the pointer(or reference) being cast is a pointer(or reference) to
either an object of the target type or an object derived from the target type.Otherwise,cast will fail. If the cast

12
fails,dynamic_cast evaluates to null if the cast involves pointers. If a dynamic_cast on reference type fails,a
bad_cast exception is thrown.
How to use a ‘dynamic_cast’
a)
Sample eg.Assume that base is a polymorphic class and that derived is derived from
base.
Base *bp,b_ob;
Derived *dp,d_ob;
bp=&d_ob;
dp=dynamic _cast<Derived*>(bp);
if(dp)cout<<”cast ok”;
b)
here the cast from the base pointer bp to the derived pointer dp works because bp is actually pointing to a derived
object.Thus,this fragment displays,cast ok.But in the next fragment, the cast fails because bp is pointing to a base
object and it is illegal to cast a base object into a derived object.
bp=&b_ob;//base pointer is pointed to the base object.
dp=dynamic_cast<derived*>(bp);
if(!dp)cout<<”cast fails”;
because the cast fails, this fragment displays, cast fails.
c)
The dynamic_cast operator can sometimes be used instead of typeid in certain cases. for eg,again assume that base is
a polymorphic base class for derived. The following fragment will assign dp the address of the object pointed to by
if and only if the object is really a derived object.
Base *bp;
Derived *dp;
//…..
if(typeid(*bp)==typeid(Derived))dp=(Derived*)bp;
In this case, a c-style cast is used to actually perform the cast. This is the safe because the if statement checks the
legality of the cast using typeid before the cast actually occurs.However,a better way to accomplish this is to replace
the typeid operators and if dp=dynamic_cast<Derived*>(bp);
d)
Because dynamic_cast succeeds only if the object being cast is either already an object of the target type or an object
derived from the target type,after this statement executes dp will contain a null or a pointer to an object of type
derived. Since dynamic_cast succeeds only if the cast is legal,it can simplify the logic in certain situations.
Static cast:
Like the conventional cast operators, the static_cast operator is used for any standard conversion of data types. It can
also be used to cast a base class pointer into derived class pointer.
Its general form is:
static_cast<type>(object)
here, type specifies the target type of the cast, and object is the object being cast into the new type.
Example:
int m=10;
double x=static_cast<double>(m);
char ch=static_cast<char>(m);
The first statement casts the variable m to type double and the second cast it to type char.
The static_cast operator performs a non_polymorphic cast.For example, it can be used for any standard
conversion.No run_time checks are performed.
void pointer
The void type of pointer is a special type of pointer. In C++, void represents the absence of type, so void pointers are
pointers that point to a value that has no type (and thus also an undetermined length and undetermined dereference
properties).
This allows void pointers to point to any data type, from an integer value or a float to a string of characters. But in
exchange they have a great limitation: the data pointed by them cannot be directly dereferenced (which is logical,
since we have no type to dereference to), and for that reason we will always have to cast the address in the void
pointer to some other pointer type that points to a concrete data type before dereferencing it.
General Syntax:
13
void* pointer_variable;
Void is used as a keyword.
Referring back to pointer definitions and usage, it is known that the data type the pointer variable defines is the same
as the data type the pointer points to. The address placed in a pointer must have the same type as the pointer.
For example:
int i;
float f;
int* exf;
float* test;
then
exf=&i;
Is correct because the address of integer variable is stored in an integer pointer.
If a we writes the statement:
exf=&f;
Then this statement produces an error. The address of the float variable is stored in an integer pointer that is
incorrect.
Similarly, if the programmer tries to place the address of an integer variable to a float pointer, such as:
test=&i;
The above statement will also show an error.
The Pointer to Void is a special type of pointer that the programmer can use to point to any data type.
Using the above example, the one declares pointer to void in this manner:
void* sample;
Using the above example’s definition and assigning the pointer to void to the address of an integer variable is
perfectly correct.
sample=&i;
Using the above example to define the pointer to void and assign the pointer to void to the address of a float variable
as below is also perfectly correct.
sample=&f;
Pointer to void, or a void pointer, is a special type of pointer that has a great facility of pointing to any data type.
There are limitations in the usage of void pointers that are explained below.
The concept of dereferencing using the operator * has been explained in an earlier section of this tutorial. The
programmer must note that void pointers cannot be de-referenced in the same manner. Direct dereferencing of void
pointer is not permitted. The programmer must change the pointer to void as any other pointer type that points to
valid data types such as, int, char, float and then dereference it. This conversion of pointer to some other valid data
type is achieved by using the concept of type-casting .

a)Standard Template Library:


The STL is a collection of generic classes and functions.
Containers are data structures that store data.
Algorithms are procedures used to process data contained in containers.
Iterators are object (pointer) that points to elements in a container.

Containers:
Sequence containers
Store elements in linear sequence. Ex – array, vector, list, deque
Associative containers
Used to automatically arrange stored data in a specific order. Uses trees. Ex – set, multiset, map, multimap
Container Adapters / Derived Containers
Special purpose containers created from normal containers
Algorithms:
Find() – search first element with specified value.
int arr[ ]={1,2,3,4,5,6,7,8};
int * ptr = find(arr,arr+8,3);
count() - counts occurrences of a specified element
int n=count(arr,arr+8,3);
sort()
14
sort(arr,arr+8);
search( ) - looks for a sequence of values, specified by one container within another container
int s[ ]={1,2,3,4,5,1,2,3};
int p[ ]={1,2,3};
int *pt=search(s,s+8,p,p+3);
merge( ) - merges 2 source containers into third
merge(src1,src1+5,src2,src2+5,dest
Iterators:
"Iterators are a generalization of pointers that allow a programmer to work with different data. structures
(containers) in a uniform manner", iterators are objects that have operator* returning a value of a type called the
value type of the
iterator.
Since iterators are a generalization of pointers it is assumed that every template function that takes iterators as
arguments also works with regular pointers.
There are five categories of iterators.
1) Random Access
2) Bidirectional
3) Forward
4) Input
5) Output
Iterators differ in the operations defined on them. Each iteratoris designed to satisfy a well-defined set of
requirements. These requirements define what operations
can be applied to the iterator. According to these requirements the iterators can be assigned to the fivecategories.
Iterator categories can be arranged from left to right to express that the iterator category onthe left satisfies the
requirements of all the iterator categories on the right (and so could be calledmore powerful).
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
#include<ctype.h>
class Book
{
private:
int Book_ID;
int Invent_bal;
int Copies_rec;
int Copies_sold;
int getCurInvent(); // Function declared as private
public:
Book(int,int,int,int);
void getData();
void putData();
};
Book::Book(int a=0,int b=0,int c=0,int d=0)
{
Book_ID=a;
Invent_bal=b;
Copies_rec=c;
Copies_sold=d;
}
void Book::getData()
{
cout<<"\nEnter The Book ID : "<<endl;
cin>>Book_ID;
cout<<"\nEnter Inventory Balance At The Beginning Of The Month : ";
cin>>Invent_bal;
cout<<"\nEnter The No. Of Copies Recieved : "<<endl;
15
cin>>Copies_rec;
cout<<"\nEnter The No. Of Copies Sold : "<<endl;
cin>>Copies_sold;
}
/* getCurInvent is private function which returns inventery balance of perticular book */
int Book::getCurInvent()
{
Invent_bal=Invent_bal+Copies_rec-Copies_sold;
return Invent_bal;
}
void Book::putData()
{
cout<<"\nBook ID : "<<Book_ID;
cout<<"\nCurrent Inventory Balance: "<<getCurInvent(); // getCurInvent Invoked
}
void main()
{
Book *b;
int n;
clrscr();
cout<<"\nHow Many Different Books You Want To Enter : ";
cin>>n;
b=new Book[n];
for(int i=0;i<n;i++)
{
cout<<"\nEnter "<<i+1<<" Book Details : ";
b[i].getData();
}
cout<<"\n\nBook Details Are : ";
for(i=0;i<n;i++)
{
cout<<"\n\n";
b[i].putData();
}
getch();
}
$$$$$$$$$$$$$$$$$
class Manager
{
private:
int ID;
char Name[30];
int DD;
int MM;
int YY;
public:
Manager(int,char*,int,int,int);
void getData();
void putData();
Manager(Employee const &);//constructor which takes Employee object as an argument
};
Manager::Manager(Employee const&E)
{
ID=E.getId();
strcpy(Name,E.getName());

16
//call to function getName() of Employee class which will //return the concatenated name which
is present in object E.
DD=E.getDD();
MM=E.getMM();
YY=E.getYY();
}
void main()
{
clrscr();
Employee e;
Manager m,m1;
e.getData();
e.putData();
m1=e; //m1 will be initialized with the existing values of object e of employee
//compiler will read it as m1.Mananger(Employee const &E)
m1.putData();
getch();
}
Container Class Derived Class
A class can contain objects of other classes. Such a class is A derived class inherits some or all of the properties of
called container class. the base class.
E.g class Alpha {……}; E.g. class A {……};
class Beta {……..}; class B : public A
class Gamma {……….};
{ Here the class B is called derived
Alpha a; //object of Alpha class of base class A.
Beta b; //object of Beta
}; Here the class Gamma is container class.
Inheritance is not involved in containership. Inheritance is involved.
Container class exhibits “has a” relationship. Derived class exhibits “is a” relationship with base class.
E.g. Manager “has a” birthdate. E.g. Manager “is an” Employee.
Base class-Employee
Derived class-Manager

17

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