Texas Instrument - Placement Paper
43. Can objects read and write themselves?
Ans: Yes! This can be explained with the help of following example:
#include
#include
class employee
{
private :
char name [ 20 ] ;
int age ;
float salary ;
public :
void getdata( )
{
cout << "Enter name, age and salary of employee : " ;
cin >> name >> age >> salary ;
}
void store( )
{
ofstream file ;
file.open ( "EMPLOYEE.DAT", ios::app | ios::binary ) ;
file.write ( ( char * ) this, sizeof ( *this ) ) ;
file.close( ) ;
}
void retrieve ( int n )
{
ifstream file ;
file.open ( "EMPLOYEE.DAT", ios::binary ) ;
file.seekg ( n * sizeof ( employee ) ) ;
file.read ( ( char * ) this, sizeof ( *this ) ) ;
file.close( ) ;
}
void show( )
{
cout << "Name : " << name
<< endl << "Age : " << age
<< endl << "Salary :" << salary << endl ;
}
} ;
void main( )
{
employee e [ 5 ] ;
for ( int i = 0 ; i <= 4 ; i++ )
{
e [ i ].getdata( ) ;
e [ i ].store( ) ;
}
for ( i = 0 ; i <= 4 ; i++ )
{
e [ i ].retrieve ( i ) ;
e [ i ].show( ) ;
}
}
Here, employee is the class whose objects can write and read themselves. The getdata( ) function has been used to get the data of employee and store it in the data members name, age and salary. The store( ) function is used to write an object to the file. In this function a file has been opened in append mode and each time data of current object has been stored after the last record (if any) in the file. Function retrieve( ) is used to get the data of a particular employee from the file. This retrieved data has been stored in the data members name, age and salary. Here this has been used to store data since it contains the address of the current object. The function show( ) has been used to display the data of employee.
44. Why is it necessary to use a reference in the argument to the copy constructor?
Ans : If we pass the copy constructor the argument by value, its copy would get constructed using the copy constructor. This means the copy constructor would call itself to make this copy. This process would go on and on until the compiler runs out of memory. This can be explained with the help of following example:
class sample
{
int i ;
public :
sample ( sample p )
{
i = p.i ;
}
} ;
void main( )
{
sample s ;
sample s1 ( s ) ;
}
While executing the statement sample s1 ( s ), the copy constructor would get called. As the copy construct here accepts a value, the value of s would be passed which would get collected in p. We can think of this statement as sample p = s. Here p is getting created and initialized. Means again the copy constructor would get called. This would result into recursive calls. Hence we must use a reference as an argument in a copy constructor.
45.
46. Virtual Multiple Inheritance:
A class b is defined having member variable i. Suppose two classes d1 and d2 are derived from class b and a class multiple is derived from both d1 and d2. If variable i is accessed from a member function of multiple then it gives error as 'member is ambiguous'. To avoid this error derive classes d1 and d2 with modifier virtual as shown in the following program.
#include
class b
{
public :
int i ;
public :
fun( )
{
i = 0 ;
}
} ;
class d1 : virtual public b
{
public :
fun( )
{
i = 1 ;
}
} ;
class d2 : virtual public b
{
public :
fun( )
{
i = 2 ;
}
} ;
class multiple : public d1, public d2
{
public :
fun( )
{
i = 10 ;
}
} ;
void main( )
{
multiple d ;
d.fun( ) ;
cout << d.i ;
}
46. Can we use this pointer in a class specific, operator-overloading function for new operator?
Ans: No! The this pointer is never passed to the overloaded operator new() member function because this function gets called before the object is created. Hence there is no question of the this pointer getting passed to operator new( ).
47. Can we allocate memory dynamically for a reference?
Ans: No! It is not possible to allocate memory dynamically for a reference. This is because, when we create a reference, it gets tied with some variable of its type. Now, if we try to allocate memory dynamically for a reference, it is not possible to mention that to which variable the reference would get tied.
48. When should I overload new operator on a global basis or a class basis?
Ans: We overload operator new in our program, when we want to initialize a data item or a class object at the same place where it has been allocated memory. The following example shows how to overload new operator on global basis.
#include
#include
void * operator new ( size_t s )
{
void *q = malloc ( s ) ;
return q ;
}
void main( )
{
int *p = new int ;
*p = 25 ;
cout << *p ;
}
When the operator new is overloaded on global basis it becomes impossible to initialize the data members of a class as different classes may have different types of data members. The following example shows how to overload new operator on class-by-class basis.
#include
#include
class sample
{
int i ;
public :
void* operator new ( size_t s, int ii )
{
sample *q = ( sample * ) malloc ( s ) ;
q -> i = ii ;
return q ;
}
} ;
class sample1
{
float f ;
public :
void* operator new ( size_t s, float ff )
{
sample1 *q = ( sample1 * ) malloc ( s ) ;
q -> f = ff ;
return q ;
}
} ;
void main( )
{
sample *s = new ( 7 ) sample ;
sample1 *s1 = new ( 5.6f ) sample1 ;
}
Overloading the operator new on class-by-class basis makes it possible to allocate memory for an object and initialize its data members at the same place.
49. How would you define a pointer to a data member of the type pointer to pointer?
Ans: The following program demonstrates this...
#include
class sample
{
public :
sample ( int **pp )
{
p = pp ;
}
int **p ;
} ;
int **sample::*ptr = &sample::p ;
void main( )
{
int i = 9 ;
int *pi = &i ;
sample s ( &pi ) ;
cout << ** ( s.*ptr ) ;
}
Here, ptr is the pointer to data member p of class sample, which in turn is a pointer pointing to an int.
50. How do I write a code to catch multiple types of exceptions in one single catch block?
Ans: The following program demonstrates the use of a single catch block to catch multiple exceptions.
#include
class test
{
} ;
class sample
{
public :
void fun1( )
{
throw 99 ;
}
void fun2( )
{
throw 3.14f ;
}
void fun3( )
{
throw "error" ;
}
void fun4( )
{
throw test( ) ;
}
} ;
void main( )
{
try
{
sample s ;
s.fun4( ) ;
s.fun1( ) ;
s.fun2( ) ;
s.fun3( ) ;
}
catch ( ... )
{
cout << "strange" ;
}
}
Here, different types of exceptions are thrown by the member functions of the class sample. While catching the exception instead of four different catch blocks we can as well define one single catch block. Note the syntax for defining the catch block, where we have used three dots (?) in the formal parameter list. This indicates that any thrown exception should get caught in the same catch block. When the exception is thrown from the fun4( ) control reaches the catch block, ignoring the rest of the calls.
51. Can we return an error value from the constructor of a class?
Ans: No. We cannot return any error value from the constructor, as the constructor doesn't have any return type. However, by throwing an exception we can pass value to catch block. This is shown in the following example:
#include
class sample
{
public :
sample ( int i )
{
if ( i == 0 )
throw "error" ;
}
} ;
void main( )
{
try
{
sample s ( 0 ) ;
}
catch ( char * str )
{
cout << str ;
}
}
In this program, the statement throw "error" ; would throw an exception when an object s of the class sample would get created. The catch block would collect the string error.
52. How do I define the member function of a template class, which has to be defined outside the template class. The function receives an object of its own class as a parameter and returns the value of the same type.
Ans: The following example shows how we can define such a function.
sample sample::fun ( sample s )
{
// code
}
Here, the first sample indicates the return type of the function and the next sample is used for the scope of function.
53. How name mangling can be prevented?
Ans: To avoid name mangling the function should be declared with an extern "C" attribute. Functions declared as extern "C" are treated as C-style functions. Hence the compiler does not mangle them. The following code snippet shows how to declare such a function.
#include
extern "C" void display( )
{
cout << "See the effect of C in C++ " ;
}
void main( )
{
display( ) ;
}
54. Can we allocate memory dynamically for a reference?
Ans: No, it is not possible to allocate memory dynamically for a reference. A reference is initialized at the time of creation. Trying to allocate memory dynamically for a reference creates a problem in initializing it. Thus, the compiler does not allow us to dynamically allocate the memory for references.
55. What is RTTI?
Ans: RTTI stands for 'Run Time Type Information'. We use virtual function mechanism where we can call derived class's member functions using base class's pointer. However, many times we wish to know the exact type of the object. We can know the type of the object using RTTI. A function that returns the type of the object is known as RTTI functions. C++ supports two ways to obtain information about the object's class at run time, they are typeid( ) operator and dynamic_cast operator.
56. What is Data Conversion?
Ans: Assignments between types whether they are basic or user-defined, are handled by the compiler. If the variables are of different basic types compiler calls a special routine to convert the value. But if we want to convert between user-defined data type and basic types we have to write conversion routine ourselves. A conversion routine to convert user-defined data type string to integer is shown below:
class string
{
private :
char str[20] ;
public :
string( )
{
}
string ( char *s )
{
strcpy ( str, s ) ;
}
operator int( )
{
return 123 ; // Write logic to convert string to integer
}
} ;
main( )
{
string s2 = "123" ;
int i1 = int ( s2 ) ;
cout << endl << i1 ;
}
57. How to obtain type information using typeid( ) operator?
Ans: typeid( ) operator takes an object, a reference or a pointer and returns its type. Following program shows how to use the typeid( ) operator.
#include
#include
class Base
{
public :
virtual void show( )
{
}
};
class Der1 : public Base
{
} ;
void main( )
{
Base *b1 ;
cout << endl << typeid ( b1 ).name( ) ;
Der1 d1 ;
b1 = &d1 ;
cout << endl << typeid ( *b1 ).name( ) ;
cout << endl << typeid ( 12 ).name( ) << endl << typeid ( 12.5 ).name( ) ;
}
The output of this program will be
Base*
Der1
int
double
RTTI operators must be used for polymorphic class (class having virtual function) only. For non-polymorphic class static type information is returned.
58. How to use RTTI with class templates?
Ans: Templates can generate different classes. We may wish to get the type of class, which we are working in. The following program shows how to use RTTI operator typeid( ) with class template.
#include
#include
template
class base
{
public :
base( )
{
cout << typeid ( *this ).name( ) << "Constructor" << endl ;
}
T add ( T a, T b )
{
return a + b ;
}
~base( )
{
cout << typeid ( *this ).name( ) << "Destructor" << endl ;
}
} ;
void main( )
{
base b1 ;
cout << b1.add ( 10, 20 ) << endl ;
base b2 ;
cout << b2.add ( 5.5, 10.5 ) << endl ;
}
59. We can use following C++ operators for typecasting. static_cast is used for castless conversions, narrowing conversions, conversion from void* and implicit type conversions. const_cast is used to convert a const to a non-const. reinterpret_cast is used to assign one kind of pointer to another.
60. What will be the output of the following program?
#include
class A
{
public :
A( )
{
cout << "Reached in Constructor\n" ;
}
} ;
void main( )
{
A a( ) ;
A b ;
}
Output : Reached in Constructor
Constructor gets called only once when the object b is created. When the
statement A a( ) ; gets executed constructor does not get called. This is because compiler takes this statement as a prototype declaration of function a( ) that returns an object of class A. However, if we pass arguments like
A a ( 10 ) ;
Compiler would search for one argument constructor and if not found would flash an error.
61. What is a container?
Ans: A container is an object that holds other objects. Various collection classes like List, Hash Table, AbstractArray, etc. are the examples of containers. We can use the classes to hold objects of any derived classes. The containers provide various methods using which we can get the number of objects stored in the container and iterate through the objects stored in it.
62. Function template overloading
One can declare several function templates with the same name and even declare a combination of function templates and ordinary functions with the same name. When an overloaded function is called, overload resolution is necessary to find the right function or template function to invoke.
For example:
template < class T > T sqrt ( T ) ;
template < class T > complex < T > sqrt ( complex < T > ) ;double sqrt ( double ) ;
void f ( complex < double > z )
{
sqrt ( 2 ) ; // sqrt < int > ( int )
sqrt ( 2.0 ) ; // sqrt ( double )
sqrt ( z ) ; // sqrt < complex < double > ( complex < double > )
}
In the same way that a template function is a generalization of the notion of a function, the rules for resolution in the presence of function templates are generalizations of the function overload resolution rules. Basically, for each template we find the specialization that is best for the set of function arguments. Then we apply the usual function overload resolution rules to these specializations and all ordinary functions.
63. Exception Handling in C++
In C++ we can handle run-time errors generated by c++ classes by using three new keywords: throw, catch, and try. We also have to create an exception class. If during the course of execution of a member function of this class a run-time error occurs, then this member function informs the application that an error has occurred. This process of informing is called 'throwing' an exception. The following code shows how to deal with exception handling.
class sample
{
public :
class errorclass
{
} ;
void fun( )
{
if ( some error occurs )
throw errorclass( ) // throws exception
}
} ;
//application
void main( )
{
try
{
sample s ;
s.fun( ) ;
}
catch ( sample::errorclass )
{
// do something about the error
}
}
64. Consider the following code:
#include
class base
{
public :
int data ;
} ;
class d1 : public base
{
} ;
class d2 : public base
{
} ;
class der : public d1, public d2
{
public :
void showdata( )
{
cout << data ;
}
} ;
void main( )
{
der d ;
d.showdata( ) ;
}
If you run this program it is bound to give you errors. This is because of the rules of inheritance:
1. Each base class not specified virtual will have its own sub-object representing it. In the above program, if we create object of d1 it will have a sub-object of class base containing a data member data. If we create an object of class der it will have sub-objects of classes d1 and d2 and both the sub-objects will refer to a separate copy of data. Hence, to access data from class der we will have to mention the class name. For example, d1::data or d2::data.
2. If we want that only one sub-object should exist we must use the concept of virtual base class. The single object of this will represent every base class of given name that is specified to be virtual class. After making d1 and d2 as virtual base class if we create an object of der only one sub-object would exist and so accessing data would no longer give us errors.
65. How to declare a pointer to a member function?
Ans: Suppose, I wish to declare a pointer to a member function that receives an int and returns an int. I will have to declare it as int (A::* ) ( int ). Following is an example.
#include
class A
{
public :
int fun ( int f )
{
cout << "in fun\n" ;
return f * f ;
}
} ;
typedef int ( A:: *pfun ) ( int ) ;
void main( )
{
pfun p = A::fun ;
A a ;
int s = ( a.*p ) ( 6 ) ;
cout << s ;
}
66. What is the disadvantage of a template function?
Ans: A template function cannot be distributed in the obj form. This is because, with which parameters the template function is going to be called is decided at the run time only. Therefore an obj form of a template function cannot be made by merely compiling it.
67. How to declare a pointer to the data members of a class?
Ans: Following program shows how to declare a pointer to non-function members of a class.
#include
class A
{
public :
int a ;
void print( )
{
cout << a ;
}
} ;
void main( )
{
int A::*pa = &A::a ;
A obj ;
obj.*pa = 20 ;
obj.print( ) ;
}
Here, we have initialised the data member a using the pointer pa.
68. How to allocate memory for a multidimensional array dynamically?
Ans: Many times we need to allocate memory for a multidimensional array dynamically. Because of complexity of pointers many find this difficult. Following program allocates memory for a 3 x 3 array dynamically, copies contents of a 3 x 3 array in it and prints the contents using the pointer.
#include
#include
int a[ ][3] = {
1, 2, 3,
4, 5, 6,
7, 8, 9
} ;
void main( )
{
int **p ;
p = new int *[3] ;
for ( int i = 0 ; i < 3 ; i++ )
p = new int[3] ;
for ( i = 0 ; i < 3 ; i++ )
for ( int j = 0 ; j < 3 ; j++ )
p[j] = a[j] ;
for ( i = 0 ; i < 3 ; i++ )
{
for ( j = 0 ; j < 3 ; j++ )
cout << p[j] ;
cout << "\n" ;
}
}
69. When should we use the :: ( scope resolution ) operator to invoke the virtual functions?
Ans: Generally, :: operator is used to call a virtual function from constructor or destructor. This is because, if we call a virtual function from base class constructor or destructor the virtual function of the base class would get called even if the object being constructed or destroyed would be the object of the derived class. Thus, whenever we want to bypass the dynamic binding mechanism we must use the :: operator to call a virtual function.
70. How do I use operators .* and ->* in a program?
Ans: The following code snippet demonstrates the use of .* and ->* operators.
#include
class sample
{
public :
int i ;
void fun( )
{
cout << "fun" << endl ;
}
} ;
void ( sample::*pf )( ) = &sample::fun ;
int sample::*pdm = &sample::i ;
void main( )
{
sample s ;
sample *p = new sample ;
( s .* pf )( ) ;
( p ->* pf )( ) ;
s .* pdm = 1 ;
p ->* pdm = 2 ;
cout << s .* pdm << endl ;
cout << p ->* pdm << endl ;
}
In the above program pf is a pointer to a function fun( ) of class sample, and
pdm is a pointer to a data member i of the same class sample. The object s of the class sample is created statically. Next, p is a pointer to an object created dynamically. The using the operator .* and ->* the member functions are called and also the public data member is accessed.