Good Questions In
C++
!!Enjoy!!!
85.
How do I call a virtual function of a class using a pointer to
a function ?
Ans :
#include <iostream.h>
class Cvirtual
{
public :
virtual float vfun( )
{
cout << "from vfun" << endl ;
return 7.03f ;
}
} ;
void main( )
{
Cvirtual obj ;
int **p = ( int ** ) &obj ;
float ( *pf1 ) ( ) ;
pf1 = ( float ( * ) ( ) ) **p ;
float f = ( *pf1 ) ( ) ;
cout << "return val = " << f << endl ;
}
In the above program class Cvirtual consists of a virtual
function vfun(). In variable p we have stored the address of
an object of class Cvirtual. While doing so, we have type
casted the address of obj to int **, because obj holds a
hidden data member called vptr, which in turn holds the
address of virtual function vfun( ). In pf1, a pointer to a
function, we are collecting the address of the virtual
function vfun( ). Thus the value returned by vfun( ) would
then get collected in f.
-------------------------------------------------------------------------------------------------
86.
Why an overloaded new operator defined in a class is static?
Ans: An overloaded new function is by default static even if
it is not declared so. This is because non-static member
functions can be called through an object only. But when an
overloaded new operator function gets called the object
doesn't stand created. Since new operator function itself is
responsible for creating the object. Hence to be able to call
a function without an object, the function must be static.
-------------------------------------------------------------------------------------------------
87.
What is a pure virtual destructor?
Ans: Like a pure virtual function we can also have a pure
virtual destructor. If a base class contains a pure virtual
destructor it becomes necessary for the derived classes to
implement the destructor. An ordinary pure virtual function
does not have a body but pure virtual destructor must have a
body. This is because all the destructors in the hierarchy of
inheritance are always called as a part of destruction.
-------------------------------------------------------------------------------------------------
88.
When we are required to find offset of an element within a
structure? or, how do we call the function of an outer class
from a function in the inner class? (The inner class is nested
in the outer class)
Ans:
#include <iostream.h>
class outer
{
int i ;
float f ;
public :
class inner
{
public :
infunc( )
{
outer *pout ;
pout = (outer*) this - ( size_t ) &( ( ( outer* ) 0 ) ->
in ) ;
pout -> outfunc( ) ;
}
} ;
inner in ;
outfunc( )
{
cout << "in outer class's function" ;
}
} ;
void main( )
{
outer out ;
out.in.infunc( )
}
In the above example we are calling outer::outfunc( ) from
inner::infunc(). To call outfunc( ) we need a pointer to the
outer class. To get the pointer we have subtracted offset of
the inner class's object (base address of outer class's
object - address of inner class's object) from address of
inner class's object.
-------------------------------------------------------------------------------------------------
89.
void f ( float n, int i = 10 ) ;
void f ( float a ) ;
void main( )
{
f ( 12.6 ) ;
}
void f ( float n, int i )
{
}
void f ( float n )
{
}
The above program results in an error (ambiguous call) since
without the default argument the two functions have arguments
that are matching in number, order and type.
-------------------------------------------------------------------------------------------------
90.
Some programs need to exercise precise control over the memory
areas where data is placed. For example, suppose we wish to
read the contents of the boot sector into a structure. For
this the byte arrangement of the
structure elements must match the arrangement of various
fields in the boot sector of the disk.
The #pragma pack directives offer a way to fulfill this
requirement. The #pragma pack directive specifies packing
alignment for structure and union members. The #pragma takes
effect at the first structure or union declaration after
the #pragma is seen. Consider the following structure:
#pragma pack (1)
struct emp
{
int a ;
float s ;
char ch ;
} ;
#pragma pack( )
Here, #pragma pack ( 1 ) lets each structure element to begin
on a 1-byte boundary. Hence the size of the structure will be
9. (int - 4, float - 4, char - 1). If we use #pragma pack ( 2
) each structure element can begin on a 2-byte boundary.
Hence the size of the structure will be 10. (int - 4, float -
4, char - 2).
-------------------------------------------------------------------------------------------------
91.
How to restrict a friend class's access to the private data
members?
Ans: If we declare a class as a friend of our class the friend
class can access the private data members of our class.
However, if we want we can restrict this access to some
selective functions of the class. Following program shows how
to achieve this:
#include <iostream.h>
class X
{
public :
void print ( class Z &z ) ;
} ;
class Z
{
private :
int i ;
public :
Z ( int ii )
{
i = ii ;
}
friend X::print ( class Z &z ) ;
} ;
void X::print ( Z &z1 )
{
cout << z1.i ;
}
main( )
{
Z z ( 10 ) ;
X x ;
x.print ( 10 ) ;
}
In the above program only the X::print( ) function can access
the private data members of class Z.
-------------------------------------------------------------------------------------------------
92.
What is name mangling?
Ans: C++ enables you to assign the same function name to more
than one functions but with different parameter types. This
feature is called function overloading. But when we give
several functions the same name, how does the compiler decide
which particular function is to be called? C++ solves this
problem by applying a process called name mangling. Name
mangling applies a decorated name to the function. The mangled
name includes tokens that identify the functions' return type
and the types of its arguments.
class test
{
public :
void fun ( int a, char b ) ;
void fun ( char *c, float y ) ;
} ;
void main( )
{
test s1 ;
s1.fun ( 65, 'A' ) ;
s1.fun ( "Anil", 5.5f ) ;
}
At the time of resolving the calls to fun( ) function the
linker would not be able to find the definition of the
overloaded function fun( ) and it would report an error. If
you look at these errors you will see the mangled names like,
(?fun@test@@QAEXJJ@Z) and (?fun@test@@QAEXMM@Z). Note that
different compilers may use different name mangling
schemes.
-------------------------------------------------------------------------------------------------
93.
How would you call a C function from C++ code?
Ans: Using extern "C".
The function prototype must be preceded by extern "C". More
than one C functions can be grouped inside braces as shown
below:
extern "C"
{
void f( ) ;
void f1( ) ;
}
// In cfunc.c
#include <stdio.h>
void f( )
{
printf ( "in f( )" ) ;
}
// In func.cpp
#include <iostream.h>
extern "C" void f( ) ;
void main( )
{
f( ) ;
}
Ensure that both .c and .cpp files are in the same
project.
-------------------------------------------------------------------------------------------------
94.
How to restrict the number of floating-point digits displayed
?
Ans: When we display floating-point values, we can use the
setprecision manipulator to specify the desired number of
digits to the right of the decimal point.
For example,
cout << setprecision ( 3 ) << 12.34678 ;
This statement would give the output as 12.347.
-------------------------------------------------------------------------------------------------
95.
What is a wild pointer ?
Ans: A wild pointer is the one that points to a garbage value.
For example, an uninitialized pointer that contains garbage
value or a pointer that refers to something that no longer
exists.
-------------------------------------------------------------------------------------------------
96.
How friend function helps to increase the versatility of
overloaded operators?
Ans: Consider the following statement,
s2 = s1 * 2 ;
where, s1 and s2 are objects of sample class. This statement
would work if the overloaded operator * ( sample s ) or
conversion function is provided in the class. Internally this
statement would get converted to,
s2 = s1.operator * ( 2 ) ;
The function materializes because it is called with an object
s1. The this pointer of s1 would get passed implicitly. To
collect 2 in s, first the compiler would call the one-argument
constructor, then it would build a
nameless object, which then would get collected in s.
However, if we write the above statement as,
s2 = 2 * s1 ;
then it won't compile. This is because the call now would get
treated as,
s2 = 2.operator * ( s1 ) ;
and 2 is not an object. The friend function helps to get rid
of such a situation. This is shown in the following program.
#include <iostream.h>
class sample
{
private :
int i ;
public :
sample ( int ii = 0 )
{
i = ii ;
}
void showdata( )
{
cout << i << endl ;
}
friend sample operator * ( sample, sample ) ;
} ;
sample operator * ( sample s1, sample s2 )
{
sample temp ;
temp.i = s1.i * s2.i ;
return ( temp ) ;
}
void main( )
{
sample s1 ( 10 ), s2 ;
s2 = s1 * 2 ;
s2.showdata( ) ;
s1 = 2 * s2 ;
s1.showdata( ) ;
}
Here the operator *( ) function takes two parameters. This is
because the operator function is no longer a member function
of the class. It is a friend of the class sample. Thus the
statement s2 = s1 * 2 ; would not take the form s2.operator *
( 2 ). This example shows that using friend permits the
overloaded operators to be more versatile.
-------------------------------------------------------------------------------------------------
97.
What is a const_cast?
Ans: The const_cast is used to convert a const to a non-const.
This is shown in the following program.
#include <iostream.h>
void main( )
{
const int a = 0 ;
int *ptr = ( int * ) &a ; // one way
ptr = const_cast <int *> ( &a ) ; // better way
}
Here, the address of the const variable a is assigned to the
pointer to a non-const variable. The const_cast is also used
when we want to change the data members of a class inside the
const member functions. The following code snippet shows how
to do this.
class sample
{
private :
int data ;
public :
void fun( ) const
{
( const_cast <sample *> ( this ) ) -> data = 70 ;
}
} ;
-------------------------------------------------------------------------------------------------
98.
Using a smart pointer we can make an object appear like a
pointer.
If a class overloads the operator -> then any object of that
class can appear like a pointer when the operator -> ( ) is
called. The following program illustrates this.
#include <iostream.h>
class test
{
public :
void fun( )
{
cout << "fun of smart pointer" ;
}
} ;
class smartpointer
{
test t ;
public :
test* operator ->( )
{
return &t ;
}
} ;
void main( )
{
smartpointer sp ;
sp -> fun( ) ;
}
The beauty of overloading operator -> is that even though sp
is an object we can make it work like a pointer. The operator
-> ( ) returns the address of the object of the type test.
Using this address of the test object the function fun( ) of
the class test gets called. Thus even though fun( ) is not a
member of smartpointer class we can still call it using sp.
-------------------------------------------------------------------------------------------------
99.
Can we apply delete on this pointer inside a member function?
Ans : Yes! If the member function of a class is called using a
pointer to an object, which is allocated dynamically, the
object would get deleted. But if the member function is called
using the object, which is allocated statically, then a
runtime error would occur. This is because we cannot call
delete on statically allocated objects. This is illustrated in
the following example.
class sample
{
private :
int i ;
public :
void fun( )
{
delete this ;
}
} ;
void main( )
{
sample *s = new sample ;
s -> fun( ) ; // no error
sample s1 ;
s1.fun( ) ; // would throw a runtime error
}
-------------------------------------------------------------------------------------------------
100.
Why can't data members of a class be initialized at the time
of declaration as given in the following code?
class emp
{
private :
int j = 10 ;
} ;
Ans: Memory for data members of a class is allocated only when
object of that class is created. One cannot store data in a
memory location, which does not exist at all. Therefore
initialization at the time of declaration
is not possible.
-------------------------------------------------------------------------------------------------
101.
Why in a copy constructor an object is collected in a
reference to object as shown below?
#include <iostream.h>
class emp
{
public :
emp( )
{
}
emp ( emp& )
{
cout << "copy" ;
}
} ;
void main( )
{
emp e ;
emp e1 = e ;
}
Ans: A copy constructor is called when an object is created
and initialised at the same time. It is also called when
object is passed to a function. So, If we pass the object to
copy constructor copy constructor would get called
recursively. Thus it will stuck up in an infinite loop.
-------------------------------------------------------------------------------------------------
102.
What is Early Binding and Dynamic Binding?
Ans: The term binding refers to the connection between a
function call and the actual code executed as a result of the
call. Early Binding: If which function is to be called is
known at the compile-time it is known as static or early
binding. Dynamic Binding: If which function is to be called is
decided at run time it is called as late or dynamic binding.
Dynamic binding is so called because the actual function
called at run-time depends on the contents of the pointer. For
example, call to virtual functions, call to functions to be
linked from dlls use late binding.
-------------------------------------------------------------------------------------------------
103.
When can we use the function ostrstream::freeze( )?
Ans: While outputting data to memory in the in-memory
formatting we need to create an object of the class ostrstream.
The constructor of ostrstream receives the address of the
buffer but if we want that the ostrstream
object should do its own memory management then we need to
create an ostrstream object with no constructor arguments as:
ostrstream s ;
Now s will do its own memory management. We can stuff as many
bytes into it as we want. If it falls short of memory, it will
allocate more memory. If it cannot, it may even move the block
of memory. When the object goes out of scope, the heap storage
is automatically released. This is a more flexible approach if
we do not know how much space we are going to need. If we want
the physical address of the memory used by s we can obtain it
by calling the str( ) member function:
char* p = s.str( ) ;
Once str( ) has been called then the block of memory allocated
by ostrstream cannot be moved. This is logical. It can't move
the block since we are now expecting it to be at a particular
location. In such a case we
say that ostrstream has freezed itself. Once frozen we can't
add any more characters to it. Adding characters to a frozen
ostrstream results in undefined behavior. In addition, the
ostrstream is no longer responsible for cleaning up the
storage. You took over that responsibility when you asked for
the char * with str( ). We can clean the storage in two ways:
Using the delete operator as shown below:
ostrstream s ;
char *p ;
p = s.str( ) ;
delete p ;
By unfreezing the ostrstream. You do this by calling freeze(
), with an argument 1. During freezing it is called with the
default argument of 0.
-------------------------------------------------------------------------------------------------