Anda di halaman 1dari 38

1) Why is C++ called object-oriented language?

C++ is called object-oriented language because C++ language views a problem in terms of objects involved rather than the procedure for doing it. An object is an identifiable entity with some characteristics and behaviors. While programming using OOP approach, the characteristics of an object are represented by its data and its behavior is represented by its functions associated. Therefore, in OOP Programming object represent an entity that can store data and has its interface through functions. Advantages of OOP Programming are that it makes the program less complex, its reuse feasible and possible

2) Differentiate between C and C++? C is a structured programming language. C++: object oriented programming language. Programmers use functions/procedures to deal with larger program in C language. In C++ programmers construct a class and related member functions to deal with large class functionality. C++ can have member functions of structures/classes. C does not support modularization of member functions. C++ can hide/abstract member variables/functions by private or protected keyword. In C language structure members can not be hidden from outside world. C never support abstraction. C++ has function and operator overloading/polymorphism feature. C language does not have polymorphism features. C also does not support inheritance.

3) Differentiate between C++ and JAVA? C++: it is dependant on windows platform JAVA: it is a platform independent programming language C++: files created in C++ are executable JAVA: A JVM (Java Virtual Machine) is required to run programs written in JAVA as it does not create executable files

4) What is encapsulation? Encapsulation is the wrapping up of data and variables (that work on the data) into a single unit (called class). The only way to access the data is provided by the functions (that are combined along with the data). These functions are called member functions in C++. If you want to read a data item in an object (an instance of the class), you call a member function in the object. It will read the item and return the value to you. The data is hidden and so is safe from accidental alteration. Encapsulation is a way of implementing data abstraction. Encapsulation hides the details of the implementation of an object.

5) What is a constructor?

A constructor is a class function with the same name as the class itself. It cannot have a return type and may accept parameters. It is a callback or event for the compiler to call the constructor after memory allocation of the object is complete via new operator. Responsibility of constructor function is to set initial values to each object members to some default values before the object can be used. Example: Here is an example of student class of standard 12. Constructor initializes the default name as blank and age of the student as 16.

#include<string.h> #include<iostream.h> class std12_student { private: int age; char name[20]; public: std12_student() { age = 18; strcpy(name, ""); } int get_age() { return age; } char* get_name() { return name; } }; int main(int argc, char* argv[]) { std12_student s; cout << "Age = " << s.get_age();//Default age = 16 return 0; }

6) What is overloaded constructor? An overloaded constructor is a constructor which takes arguments. It is also called parameterized constructor. Example: Example: Here is an example of student class of standard 12. Default Constructor initializes the default name as blank and age of the student as 16. Overloaded constructor has provisions to give name and age as arguments during construction.

#include<string.h> #include<iostream.h> class std12_student { private: int age; char name[20];

public: /*Default Constructor*/ std12_student() { age = 18; strcpy(name, ""); } /*Overloaded Constructor 1*/ std12_student(char *student_name) { age = 18; strcpy(name, student_name); } /*Overloaded Constructor 2*/ std12_student(char *student_name, int student_age) { age = student_age; strcpy(name, student_name); } int get_age() { return age; } char* get_name() { return name; } }; int main(int argc, char* argv[]) { std12_student s("ABC", 17); cout << "Name : " << s.get_name() << "Age = " << s.get_age(); return 0; }

7) What is a destructor? A destructor is a special function member of a class that is automatically called when an object about to be deleted by delete operator. It always has the same name as the class preceded by a tilt ~ symbol and has no return type. It is used to free allocated memory used by an object. It takes no arguments. Example:

#include<string.h> #include<iostream.h> class student { private: char *name; public: student() { name = (char *)new char[20];

if(name) { strcpy(name, ""); } else { name = NULL; } } char* get_name() { return name; } void set_name(char *student_name) { if(name && student_name) { strcpy(name, student_name); } return; } }; int main(int argc, char* argv[]) { student * s_ptr; s_ptr = new student(); if(s_ptr) { s_ptr->set_name("ABC"); cout << "Student Name : " << s_ptr->get_name(); delete s_ptr; } else { cout << "Memory allocation error"; } return 0; }

8) Can a destructor be overloaded? A destructor can never be overloaded. An overloaded destructor would mean that the destructor has taken arguments. Since a destructor does not take arguments, it can never be overloaded. 9) What is a copy constructor? In addition to providing a default constructor and a destructor, the compiler also provides a default copy constructor which is called each time a copy of an object is made. When a program passes an object by value, either into the function or as a function return value, a temporary copy of the object is made. This work is done by the copy constructor. All copy constructors take one argument or parameter which is the reference to an object of the same class. The default copy constructor copies each data member from the object passed as a parameter to the data member of the new object.

Example:

#include<string.h> #include<iostream.h> class number { private: int n; public: number(int d) { n=d; } number(number &a) { n = a.n; cout << "The copy constructor:"; } void display() { cout << "The number = " << n; } }; void main() { number n1(10); number n2(n1);/*copy constructor called*/ cout << "object n1:"; n1.display(); cout << "object n2:"; n2.display(); }

10) What is shallow copy? Shallow Copy: Default copy constructor of compiler copies all the member variables from source to destination object. This is called shallow copy constructor. Example:

#include<string.h> #include<iostream.h> class C { public: int var1; }; void main(int argc, char *argv[]) { C c1; c1.var1 = 1; C c2(c1); cout << "value of c2.val " << c2.val; }

11) What is deep copy constructor? Deep Copy: Overriding default copy constructor with a constructor which copies all the members including all dynamically allocated members is called deep copy constructor. Example

#include<string.h> #include<iostream.h> class User { protected: int user_id; char *user_name; public: User() { user_id = 0; user_name = new char[10]; } ~ User() { user_id = 0; delete [] user_name; } int get_id() { return user_id; } void set_id(int id) { user_id = id; } char* get_name(void) { return user_name; } void set_name(char* name) { strcpy(user_name, name); } User(User &u) { user_id = u. user_id; user_name = new char[10]; strcpy(user_name, u.user_name); } User & operator = (User &u) { user_id = u. user_id; strcpy(user_name, u.user_name); return *this; } };

void main(int argc, char *argv[]) { User user1; user1.set_id(1); user1.set_name("User1"); User user2(user1); cout << "User1 id " << user1 .get_id() << ", User1 name " << user1 .get_name() << endl; cout << "User2 id " << user2 .get_id() << ", User2 name " <<user2 .get_name() << endl; cout.flush(); user1.set_id(2); user2.set_name("User2"); cout << "User1 id " << user1.get_id() << ", User1 name " << user1 .get_name() << endl; cout << "User2 id " <<user2.get_id() << ", User2 name "<<user2 .get_name() << endl; cout.flush(); }

12) Differentiate between deep copy constructor and shallow copy constructor? Deep copy vs Shallow copy: Deep Copy copies all the dynamically allocated members properly to destination. Deep copy is safe and prevents memory corruptions or memory overwriting. When dealing with string, list, vectors, or any other dynamically allocated members deep copy is mandatory. Example: Comment out the below functions in the following example and see how you face problem at runtime. 1. 2. 3.

#include<string.h> #include<iostream.h> class User { protected: int user_id; char *user_name; public: User() { user_id = 0; user_name = new char[10]; } ~ User() { user_id = 0; delete [] user_name; } int get_id() { return user_id; } void set_id(int id) { user_id = id;

} char* get_name(void) { return user_name; } void set_name(char* name) { strcpy(user_name, name); } /*Comment out this function*/ User(User &u) { user_id = u. user_id; user_name = new char[10]; strcpy(user_name, u.user_name); } /*Comment out this function*/ User & operator = (User &u) { user_id = u. user_id; strcpy(user_name, u.user_name); return *this; } }; void main(int argc, char *argv[]) { User user1; user1.set_id(1); user1.set_name("User1"); User user2(user1); cout << "User1 id " << user1 .get_id() << ", User1 name " << user1 .get_name() << endl; cout << "User2 id " << user2 .get_id() << ", User2 name " <<user2 .get_name() << endl; cout.flush(); user1.set_id(2); user2.set_name("User2"); cout << "User1 id " << user1.get_id() << ", User1 name " << user1 .get_name() << endl; cout << "User2 id " <<user2.get_id() << ", User2 name "<<user2 .get_name() << endl; cout.flush(); }

13) What is the design of singleton class? Singleton class does not support object creation/deleting using new and operator. Thus the constructor and destructor have to be private so that it can prevent user from doing so. In most of the design singleton class provides a interface function like GetInstance() to return an instance to the outside world and also a Release() function to inform the class server that client has finished using this object. Also a global object retention count has to be there to monitor the reference count of the object usage. At the very beginning, reference count will be zero and global object pointer is NULL. When a first client calls

GetInstance() it allocates the object and increments the reference count by one. If another GetInstance() call comes it does not allocate another object, instead it returns the existing global instance and increments the reference count. Now client calls Release() whenever client finishes using the object . Suppose we have reference count equal to 2. New client calls Release(). At this time it decrements the reference count by one. Thus count will be 1. Now the last client calls Release() and object reference count becomes zero. Now there is no client active. Thus holding the object in memory is a wastage. We can now safely release the memory. There is also one design aspect when dealing in multi-threading/multi-programming environment. We must handle the increment and decrement of the reference count in a thread-safe manner. We must use a critical section inside GetInstance() and Release() function when referring the global reference count. Example:

class singleton { private: static singleton *self; static unsigned int ref_count; singleton() { ref_count = 0; } ~singleton() { ref_count = 0; } public: static singleton * GetInstance(void); void Release(void) { /*Start of critical section*/ if(self) { ref_count--; if(ref_count == 0) { delete self; } } /*End of critical section*/ } }; singleton * singleton::GetInstance(void) { /*Start of critical section*/ if(!self) { self = new singleton(); } ref_count++; return self; /*End of critical section*/ }

singleton * singleton::self = NULL; unsigned int singleton::ref_count = 0; void main(int argc, char *argv[]) { singleton *s_ptr1, *s_ptr2; /*ref_count = 0 -> 1, self = NULL -> allocated*/ s_ptr1 = singleton::GetInstance(); /*ref_count = 1 -> 2, self = no allocation*/ s_ptr2 = singleton::GetInstance(); /*ref_count = 2 -> 1, self = no de-allocation*/ s_ptr1->Release(); /*ref_count = 1 -> 0, self = de-allocated, -> NULL*/ s_ptr2->Release(); }

14) What is the default access modifier for class members and member functions in a class? In a class, the default access modifier for class member and member functions is private. Private members are the class members (data members and member functions) that are hidden from the outside world. The private members implement the concept of OOP called data hiding.

15) What is the difference between a C structure and a C++ class? C structures cannot have member function while C++ class always has. C structures must have at least one data member in it to compile. C++ class can be empty. It is possible to have a C++ class without member variables and member functions. Static member variables are not allowed in C structures. C++ can have static members. 16) What is the default access modifier for structure members and member functions in a structure? In a class, the default access modifier for class member and member functions is public. Public members are the class members (data members and member functions) that are open to the outside world. The public function members implement the concept of interfaces in object oriented programming.

17) What is abstraction or data hiding? Abstraction or Data hiding refers to the act of representing essential features without including the background details or explanation. Example: While driving a car, we only know the essential features of the car like gear handling, steering handling, use of clutch, accelerator, and brakes etc. but we do not get into internal details like wiring, engine/motor works etc.

Class car { public: /*Public interfaces*/ int get_gear_count(void); int turn_left(void);

int turn_right(void); int go_straight(void); int set_speed(int kmh); int get_speed(int kmh); int do_break(void); private: /*Private hidden members*/ int steering_direction; int engine_speed; int break_value; int current_gear; };

18) What is 'this' pointer? The member functions of every object have access to a pointer named this, which points to the object itself. When we call a member function, it comes into existence with the values of this set to the address of the object for which it was called. This pointer is the default hidden and implicit argument of any non-static member function. Using a this pointer any member function can find out the address of the object of which it is a member. It can also be used to access the data in the object it points to. The following program shows the working of the this pointer.

class example { private: int i; public: void setdata(int i) { this->i = i; cout << "my objects address is: " << this << endl; } void showdata() { cout << "my objects address is: " << this << endl; cout << this->i; } }; void main() { example e1; e1.setdata(10); e1.showdata(); }
Output will be: my objects address is 0x8fabfff410 my objects address is 0x8fabfff410 10

We can confirm from output that each time the address of the same object e1 is printed. Since the this pointer contains the address of the object, using it we can reach the data member of the example class.

19) What is a static function? In C language if the keyword static appears before any function declaration, it means that the function will now have a file scope or private scope. That is, the static function can be accessed only in the file that declares it. This means, the function is not known outside its own file. Another file may use the same name for a different function. However in C++ the meaning of static is not the same. Here static member functions are those functions that can be called without any object creation. Scope resolution operator is used to call a static member function. Example:

class C { public: static void static_function(void) { } }; void main(int argc, char *argv[]) { C::static_function();/*Object not needed*/ }

20) Why 'this' pointer will not be created for a static function? This pointer is available to each member function as a hidden implicit argument. It is the object address value as a pointer. For static functions there is no object address at all because static function can be called even before creation of any object using scope resolution operator. Even calling with an object pointer will not associate any this pointer to it. Thus this pointer is not available in any static function. Example:

class C { public: static void static_function(void) { } }; void main(int argc, char *argv[]) { C::static_function();/*Object not needed*/ }

21) What is scope resolution operator? Scope resolution operator, symbol ::, is an operator in C++ which specifies that the scope of the function is restricted to the particular class.

Use of scope resolution operator: Return-type Class-name :: function-name (parameter list) { function body } Example:

float calc :: sum(float a, float b) { float sum; sum = a + b; return sum; }

22) What is an inline function in C++? The inline functions are a C++ enhancement designed to speed up programs. The coding of normal functions and inline functions is similar except that inline functions definitions start with the keyword inline. The distinction between normal functions and inline functions is the different compilation process. Working: After writing any program, it is first compiled to get an executable code, which consists of a set of machine language instructions. When this executable code is executed, the operating system loads these instructions into the computers memory, so that each instruction has a specific memory location. Thus, each instruction has a particular memory address. After loading the executable program in the computer memory, these instructions are executed step by step. When the function call instruction is encountered, the program stores the memory address of the instructions immediately following the function call statement, loads the function being called into the memory, copies argument values, jumps to the memory location of the called function, executes the function codes, stores the return value of the function, and then jumps back to the address of the instruction that was saved just before executing the called function. The C++ inline function provides an alternative. With inline code, the compiler replaces the function call statement with the function code itself (process called expansion) and then compiles the entire code. Thus, with inline functions, the compiler does not have to jump to another location to execute the function, and then jump back as the code of the called function is already available to the calling program. Example:

inline void max(int a, int b) { cout << (a > b ? a : b); } int main() { int x, y; cin >> x >> y; max(x, y);

23) What is the difference between a private member and a protected member? Private members are class members that are hidden from the outside world. The private members implement the OOP concept of data hiding. The private member of a class can be used only by the member functions of the class in which it is declared. Private members cannot be inherited by other classes. Protected members are the members that can only be used by the member functions and friends of the class in which it is declared. The protected members cannot be accessed by non member functions. Protected members can be inherited by other classes.

24) What is a const function? If a member function of a class does not alter any data in the class, then this member function may be declared as a constant function using the keyword const. Consider the following declarations:

int max(int,int) const; void prn(void) const;


Once a function is declared as const, it cannot alter the data values of the class. The complier will generate an error message if such functions try to change the data value.

25) What is polymorphism? Polymorphism is the ability for a message or data to be processed in more than one form. Polymorphism is the property by virtue of which the same message can be sent to objects of several different classes, and each object can respond in a different way dependent on its class. Example: the function area can be used to find area of several geometrical figures like circle, triangle or square.

26) What is operator overloading? The functions of most built-in operators can be redefined in C++. These operators can be redefined or overloaded globally or in a class by class basis. Overloaded operators are implemented as functions and can be class-member or global functions. The name of an overloaded operator is operatorx, where x is the operator. For example, to overload the addition operator, you define a function called operator+. Similarly, to overload the addition/assignment operator, +=, define a function called operator+=. Although these operators are usually called implicitly by the compiler when they are encountered in code, they can be invoked explicitly the same way as any member or nonmember function is called.

27) What is function overloading?

With the C++ language, you can overload functions and operators. Overloading is the practice of supplying more than one definition for a given function name in the same scope. The compiler is left to pick the appropriate version of the function or operator based on the arguments with which it is called. For example:

double max( double d1, double d2 ) { return ( d1 > d2 ) ? d1 : d2; } int max( int i1, int i2 ) { return ( i1 > i2 ) ? i1 : i2; }
The function max is considered an overloaded function. It can be used in code such as the following:

main() { int i = max( 12, 8 ); double d = max( 32.9, 17.4 ); return 0; }


In the first case, where the maximum value of two variables of type int is being requested, the function max( int, int ) is called. However, in the second case, the arguments are of type double, so the function max( double, double ) is called.

28) What is overriding? Base class functionality used to get inherited to child classes. Thus if a function is there in base class and a child has been inherited from it, it calls the base function. If child wants to overwrite the base functionality, it should declare the exact prototype in child class as that of the base. Now onwards compiler will use only the child function when applicable. This mechanism is called overriding. Example: Suppose we have a class base(version:1.0) and a member function to display version number named print_version(). Now suppose we have a new functional class child(version: 1.1) inherited from base. If we do not override the function print_version(), it will continue to show version number 1.0. Thus we need to override the function to display new version number. Compiler ensures that old function will be overwritten with this new version of child class.

// version : 1.0 class base { public: void print_version(void) { cout << " version: v.1.0"; } }; // version : 1.1 class child : public base

{ public: void print_version (void) { cout << " version: v.1.1"; } }; void main() { child c1; c1. print_version (); }

29) How can I distinguish between prefix increment and postfix increment? Prefix increment prototype syntax: void operator ++(); Postfix increment prototype increment: void operator ++(int); Example:

class pre_post { public: void operator ++(void) { cout << "Prefix ++ called"; } void operator ++(int) { cout << "Postfix ++ called"; } }; void main(int argc, char *argv[]) { pre_post b; b++; ++b; }

30) What is a friend class? The concept of encapsulation and data hiding indicate that nonmember functions should not be able to access an objects private and protected data. The policy is if you are not a member, you cant get it. But there is a certain situation wherein you need to share your private or protected data with nonmembers. Friends come here as a rescue. A friend class is a class whose member functions can access another class private and protected members. Ex.:

class ABC { private: int x; int y; public: void getvalue(void) { cout << "Enter the values : "; cin >> x >> y; } friend float avg(ABC A); }; float avg(ABC A) { return float(A.x + A.y)/2.0; } int main() { ABC obj; Obj.getvalue(); float av; av = avg(obj); cout << "Average = " << av; return 0; }

31) What is a friend function? The concept of encapsulation and data hiding indicate that nonmember functions should not be able to access an objects private and protected data. The policy is if you are not a member, you cant get it. But there is a certain situation wherein you need to share your private or protected data with nonmembers. Friends come here as a rescue. A friend function is a non-member function that grants access to classs private and protected members. Pointers for friend functions:

A friend function may be declared friend of more than one class. It does not have the class scope as it depends on functions original definition and declaration. It does not require an object (of the class that declares it a friend) for invoking it. It can be invoked like a normal function. Since it is not a member function, it cannot access the members of the class directly and has to use an object name and membership operator (.) with each member name. It can be declared anywhere in the class without affecting its meaning. A member function of the class operates upon the members of the object used to invoke it, while a friend function operates upon the object passed to it as argument.

32) What is the size of a class having one or more virtual functions? The sizeof() class with no virtual function inside it, is equal to the sum of all sizes of the member variable. For a class with one or more virtual functions the sizeof() class is the sizeof() class plus the sizeof(void *). This extra size is for the hidden member called vptr which is a pointer, points to vtable. Example:

class C1 { short i; void funct(); }; class C2 { short i; virtual void funct(); };


C1: size of class C1 is 2 or sizeof(short). C2: size of class C2 is sizeof(short) + sizeof(void *) that is 2 + 4 = 6 for 32bit compiler. Because this extra 4 byte is used as a hidden vptr member of the class.

33) What is a virtual pointer or vptr and vtable? C++ compiler creates a hidden class member called virtual-pointer or in short vptr when there are one or more virtual functions. This vptr is a pointer that points to a table of function pointers. This table is also created by compiler and called virtual function table or vtable. Each row of the vtable is a function pointer pointing to a corresponding virtual function. To accomplish late binding, the compiler creates this vtable table for each class that contains virtual functions and for the class derived from it. The compiler places the addresses of the virtual functions for that particular class in vtable. When virtual function call is made through a base-class pointer, the compiler quietly inserts code to fetch the VPTR and look up the function address in the VTABLE, thus calling the right function and causing late/dynamic binding to take place.

class base { virtual void funct1(void); virtual void funct2(void); }; base b;


b.vptr = address of b.vtable b.vtable[0]= &base::funct1() b.vtable[1]= &base::funct2() VPTR VTABLE FUNCTION

b.vptr -> Vtable[0] -> base::funct1() Vtable[1] -> base::funct2()

34) How does virtual function work? Understanding vfptr and vtable using C. C++ compiler creates a lot of abstraction while constructing this vfptr, vtable and also while calling a virtual function of a class. To understand how this virtual function works, we have illustrated each section below with examples and with C language.

In the below example we have an example of a base class called CShape. This is an abstract base class. An abstract base class or ABC is a class which contains at least one pure virtual function.

class CShape { public: CShape(); virtual void Draw(void) = 0; };


Now we have derived two new shapes called CCircle and CRectangle from CShape.

class CCircle : public CShape { protected: int x, y, r; public: CCircle(int x, int y, int r); virtual void Draw(void); }; class CRectangle : public CShape { protected: int x, y, w, h; public: CRectangle(int x, int y, int w, int h); virtual void Draw(void); };
In object oriented environment we always use an abstract base class pointer to point the derived object and call base function and the corresponding derived class function get called. This is why we use virtual function, with base pointer we call the virtual function and the derived class function gets called.

/* ------ CShape ----- */ CShape::Construct() { printf("Constructing an abstract shape\n"); } /*-------------------*/ /* CCircle */ CCircle::CCircle(int x, int y, int r) { this->x = x; this->y = y; this->r = r; printf("Constructing CCircle x = %d, y = %d, r = %d\n", this->x, this->y, this->r); } void CCircle::Draw(void) { printf("Drawing CCircle x = %d, y = %d, r = %d\n",

this->x, this->y, this->r); } /*-------------------*/ /* ------ CRectangle ----*/ CRectangle::CRectangle(int x, int y, int w, int h) { this->x = x; this->y = y; this->w = w; this->h = h; printf("Constructing Rectangle x = %d, y = %d, w = %d, h = %d\n", this->x, this->y, this->w, this->h); } void CRectangle::Draw(void) { printf("Drawing Rectangle x = %d, y = %d, w = %d, h = %d\n", this->x, this->y, this->w, this->h); } /*-------------------*/ CShape *shapes[2]; shapes[0] = new CCircle(x1, y1, r); shapes[1] = new CRectangle(x2, y2, w, h); //Now we call Draw() for both the shapes for(i = 0; i < 2; i++) { shapes[i]->Draw(); } Result: Constructing an abstract shape Constructing CCircle x = 10, y = 20, r = 100 Constructing an abstract shape Constructing Rectangle x = 100, y = 100, w = 50, h = 40 Drawing CCircle x = 10, y = 20, r = 100 Drawing Rectangle x = 100, y = 100, w = 50, h = 40
The result is that, with base class pointer, without knowing the type of shapes, we called the Draw()[inside for loop] and with a magic it called the corresponding Draw() for each derived classes, like for Circle it called Draw() of CCircle and for rectangle it called Draw() of CRectangle, although for each time pointer is of CShape(base). Now the point is, how it knows which function to call? Also how base pointer is related to the derived objects function address? To elaborate this I want to use C language and some code using structure. Suppose we have a structure CShape. How I can relate the Draw() function to this structure? The answer is simple, taking a function pointer inside the structure.

struct CShape { void (*Draw)(void); };


The problem with this approach is, each time I will add a new virtual function the size of the structure is going to increase by sizeof pointer. Like below if I add three virtual functions I am going to increase the size of structure by sizeof pointer x 3 thus each object of this type will consume this much of memory.

struct { void void void ... };

CShape (*Draw)(void); (*Draw1)(void); (*Draw2)(void);

The solution is we can take one and only one pointer inside the structure to point to an array/table of function pointers. If we add more and more virtual functions, the size of the structure or object is not going to increase as it only holds the pointer to the table. But the size of the function pointer table will grow. This is acceptable as we increase the number of virtual function the table which records the location of the functions will surely going to increase. Now we have our picture ready as follows.

struct CShape { struct CShape_vtable *vfptr; };


This vfptr is called pointer to vtable. This is the first hidden member of any C++ class which has one or more virtual function.

struct { void void void ... };

CShape_vtable (*Draw)(void); (*Draw1)(void); (*Draw2)(void);

vfptr points to a list/table or structure of function pointers also called vtable. This list/table is a built-in feature of C++ compiler. It holds the address of virtual functions for a particular class. Each class has its own vtable and vtable assignment is done by compiler after constructor is called and vtable gets deassigned before destructor is called. Now we will have our CShape, CCircle, CRectangle C++ code rewritten in C. This code is very elaborate and there has been given all the steps which compiler does for object construction. This will give a clear understanding.

/* ------ CShape ----- */ struct CShape_vtable; struct CShape {

struct CShape_vtable *vfptr; }; struct CShape_vtable { void (*Draw)(void); }; void CShape_Construct(struct CShape *_this) { printf("Constructing an abstract shape\n"); } /*-------------------*/ /* CCircle */ struct CCircle_vtable; struct CCircle { struct CCircle_vtable *vfptr; int x, y, r; }; struct CCircle_vtable { void (*Draw)(void); }; void CCircle_Construct(struct CCircle *_this, int x, int y, int r) { _this->x = x; _this->y = y; _this->r = r; printf("Constructing CCircle x = %d, y = %d, r = %d\n", _this->x, _this->y, _this->r); } void CCircle_Draw(struct CCircle *_this) { printf("Drawing CCircle x = %d, y = %d, r = %d\n", _this->x, _this->y, _this->r); } /*-------------------*/ /* ------ CRectangle ----*/ struct CRectangle_vtable; struct CRectangle { struct CRectangle_vtable *vfptr; int x, y, w, h; }; struct CRectangle_vtable { void (*Draw)(void); }; void CRectangle_Construct(struct CRectangle *_this, int x, int y, int w, int h) { _this->x = x; _this->y = y;

_this->w = w; _this->h = h; printf("Constructing Rectangle x = %d, y = %d, w = %d, h = %d\n", _this->x, _this->y, _this->w, _this->h); } void CRectangle_Draw(struct CRectangle *_this) { printf("Drawing Rectangle x = %d, y = %d, w = %d, h = %d\n", _this->x, _this->y, _this->w, _this->h); } /*-------------------*/ ///Main code, C++ code has been commented. struct CShape *shapes[2]; //v-table construction, Built-in compiler hidden code struct CShape_vtable csvtable; struct CShape_vtable ccvtable; struct CRectangle_vtable crvtable; csvtable.Draw = 0;//Pure virtual function ccvtable.Draw = &CCircle_Draw; crvtable.Draw = &CRectangle_Draw; //C++ Code //shapes[0] = new CCircle(x1, y1, r); //Memory allocation shapes[0] = (struct CShape *)malloc(sizeof(struct CCircle)); CShape_Construct(shapes[0]); // CShape Base Constructor call shapes[0]->vfptr = &csvtable; //CShape v-table assignment CCircle_Construct(shapes[0], x1, y1, r); //CCircle Derived Constructor call shapes[0]->vfptr = &ccvtable; // CCircle v-table assignment //C++ Code ////shapes[1] = new CRectangle(x2, y2, w, h); //Memory allocation shapes[1] = (struct CShape *)malloc(sizeof(struct CRectangle)); CShape_Construct(shapes[1]); //CShape Base Constructor call shapes[1]->vfptr = &csvtable; // CShape v-table assignment CRectangle_Construct(shapes[1], x2, y2, w, h); // CRectangle Derived Constructor call shapes[1]->vfptr = &crvtable; // CRectangle v-table assignment //Now we call Draw() for both the shapes for(i = 0; i < 2; i++) { shapes[i]->vfptr->Draw(shapes[i]); }
See here the call of the virtual function Draw(). Compiler calls the function pointer from the vtable through vfptr which is inside the object. Compiler calls a virtual function in three steps and they are 1. Get the vfptr, 2. Goto the vtable and take the proper function pointer from the offset,/LI> 3. Call the function using the pointer./LI> Note: These are compiled and tested in VC++ 6.0.

35) What is early binding and late binding? Early binding: When a non virtual class member function is called, compiler places the code to call the function by symbol name. Thus the function call jumps to a location that is decided by compile time or link time.

class base { void funct1(void); }; base b; b.funct1(); //compiler call address of base::function() symbol
Late binding: When virtual function call is made through a base-class pointer, the compiler quietly inserts code to fetch the VPTR and look up the function address in the VTABLE, thus calling the right function and this is called late/dynamic binding.

class base { virtual void funct1(void) = 0; }; class derived: public base { void funct1(void){} }; class derived2: public base { void funct1(void){} }; derived d; base * b = d; //See how b calls function funct1() of d in three steps //1) get d::vtable address from b::vptr // [value: b::vptr points to d::vtable] //2) get b::funct1() address from b::vtable entry 0 // [value: function address= d::vtable[0]] //3) call pointer entry 0 of vtable 0 // [ call address pointed by d::vtable[0] ] b->funct1(); derived2 d2; base * b = d2; //See how b calls function funct1() of d2 in three steps //1) get d2::vtable address from b::vptr // [value: b::vptr points to d::vtable] //2) get b::funct1() address from b::vtable entry 0 // [value: function address= d::vtable[0]] //3) call pointer entry 0 of vtable 0 // [ call address pointed by d::vtable[0] ] b->funct1();
From the above two function call we are clear that we are able to deal with d::vtable and able to call d::funct1() as well as d2::vtable and d2:funct1() accordingly with a single base pointer and the call binding of individual member function was at run time not compile time.

36) What is inheritance? Inheritance is the capability of one class of things to inherit capabilities or properties from another class. Ex: The class car inherits some of its properties from the class Automobiles which inherits some of its properties from another class Vehicles. The capability of passing down properties allows us to describe things in an economical way. C++ expresses this inheritance relationship by allowing one class to inherit from another. The class from which functions are derived is called base class while the class which derives the functions is called sub class.

37) Can a virtual function call from a constructor/destructor work properly? Class vptr pointer is assigned to vtable after constructor is called. Also vptr pointer is de-assigned from vtable before calling destructor. Thus virtual function calling mechanism does not work in constructor and destructor of the derived class. 38) What is a virtual destructor and its utility? Virtual destructor in base class ensures that the destructor of derived class will be called when using base pointer to the object. Suppose we have a base class and a derived class

class base { public: base() { cout << "base construction"; } ~base() { cout << "base destruction"; } }; class derived : public base { char *name; public : derived () { cout << "derived construction"; name = new char[10]; cout << "mem allocated for name"; } ~ derived () { cout << "derived destruction"; delete [] name; cout << "mem de-allocated for name"; } }; void main() { base *b = new derived(); delete b;

}
output:

base construction derived construction mem allocated for name base destruction
Here derived destruction is missing. Thus derived destructor is not getting called by compiler as it is early/compile time bind. As the type of the object is base, only base destructor is getting called. This also leads to memory leak as string member name is not getting de-allocated. To ensure proper destructor sequence call we must make the base destructor virtual. This ensures dynamic/runtime binding of the destructor through vtable mechanism After modifying the prototype ~base() to virtual ~base() the sequence will be as expected as below.

class base { public: base() { cout << "base construction"; } virtual ~base() { cout << "base destruction"; } }; Output after this change: base construction derived construction mem allocated for name derived destruction mem de-allocated for name base destruction

39) What is a virtual base class? We derive a class 'class3' from 'class1' and 'class2' which in turn have been derived from a base class 'base'. If a member function of 'class3' wants to access data or function in the base class, it hits a deadlock. Since 'class1' and 'class2' are both derived from 'base', each inherits a copy of 'base' and each copy, called subobject, contains its own copy of 'base's data. Now when 'class3' refers to the data in the 'base' class, it is unclear to the compiler which copy to access and hence reports an error. To get rid of this situation, we make 'class1' and 'class2' as virtual base classes. Using keyword virtual in the two base classes causes them to share the same sub-object of the base class and then 'class1' and 'class2' are known as virtual base class. Example: Program showing use of virtual base class.

#include<iostream.h> class base { protected: int data; public: base()

{ data = 500; } }; class class1 : virtual public base { }; class class2 : virtual public base { }; class class3:public class1, public class2 { public: int getdata() { return data; } }; void main() { class3 c; int a; a = c.getdata(); cout << a; }

40) How can I overload global << and >> operators to work with cin,cout,cerr etc?

friend ostream &operator << (ostream &apm;s, complex &apm;c); friend istream &operator >> (istream &apm;s, complex &apm;c); ostream &operator << (ostream &s, complex &c) { s << ( << c.real << , << c.imag << ); return s; }

41) What is an exception? Exception generally refers to some contradictory or unexpected situation or in short an error that is unexpected. 42) What is stack unwinding operation in exception handling? When we enclose a block of code with a try statement compiler creates a step to store current context of the CPU in current stack frame with program counter pointed to start of catch block. If the CPU encounters any error it retrieves the context from stack an program counter jumps to catch statement. This mechanism is called unwinding operation during occurrence of any exception.

43) How is exception handling done in C++? Exception handling is a nice and transparent way to handle errors in programs. For exception handling in C++, the block code to be written is enclosed in a try block. Within the try block, we can throw any occurring errors with throw command. Immediately after the try block, catch block starts wherein error

handling code is placed. Thus we can say that there are three keywords for exception handling in C++. These are: Try: A try block is a group of C++ statement enclosed in curly braces {}, which may cause (or throw) an exception. Catch: A catch block is a group of C++ statement that is used to handle a specific raised exception. Catch block should be laced after each Try block. A Catch block is specified by the following: The keyword catch A catch expression, which corresponds to a specific type of exception that may be thrown by the Try block. A group of statements enclosed within braces{} to handle the exception Throw: This statement is used to throw an exception. A Throw statement specified with: The keyword throw An assignment expression; the type of the result of this expression determines which catch bock receives control. Format:

try { //: throw exception; } catch(type exception) { //code to be executed in case of exception. }

44) Can you write a try-catch block that will catch all type of exceptions? A try-catch block can be defined which will capture all the exceptions independently of the data type used in the call to throw. For that, we need to write three dots (...) in place of the parameter type and name accepted by catch.

try { //code here } catch(...) { cout << "Exception occurred"; }

45) What is namespace? While writing big programs involving several programmers, things are likely to go out of hand if proper control is not exercised over visibility of these names.

//mylib.h char fun() void display(); class CMath{...};

//somelib.h class CMath{...}; void display();


If both these header files are included in a program, there would be a clash between the two CMath classes. A solution would be to create long names which have lesser chances of clashing but the programmers are required to type these long names. But C++ provides a better solution through a keyword named namespace. C++ provides a single global name spaces. The global name space can be sub-divided into more manageable pieces using name space feature in C++.

//mylib.h namespace myheader { char fun() void display(); class CMath{...}; } //somelib.h namespace somelib { class CMath{...}; void display(); }
The class names will not clash as they become mylib::CMath and somelib::CMath respectively. Same thing would happen to the function names. 46) How can I change a member variable within a const function? A member variable can be changed from a constant function only if the name of the function is preceded by the keyword mutable.

47) What is mutable keyword and how is it used? The data members of a constant object cannot be changed. If we want some data members to change even when the object is constant, it can be using mutable keyword. The following function shows the use of mutable keyword:

#include<iostream.h> #include<string.h> class mobile { char model[20]; mutable char owner[20]; int yrofmfg; char mobilereg[10]; public: mobile(char *m, char *o, int y, char *r) { strcpy(model, m); strcpy(owner, o); yrofmfg = y; strcpy(regno, r); } void changeowner(char *o) const {

strcpy(owner, o); } void changemodel(char *m) { strcpy(model,m); } void display() const { cout << model << endl << owner << endl << yrofmfg << endl << regno; } }; void main() { const mobile c1("E250", "Gupta", 2006, "KX091EXW342"); c1.display(); c1.changeowner("Ghosh"); c1.display(); }
when the mobile is sold its owner would change but other attributes would remain the same. Since c1 is declared const, none of the data member would change. An exception however has been made in case of owner since its declaration has been preceded by keyword mutable which makes it vulnerable to change. 48) What does the keyword 'explicit' do? Why is it used? Data conversion from standard type to user-defined type is possible through conversion operator and he classs constructor. But some conversion may take place which we dont want. To prevent conversion operator from performing unwanted conversion, we avoid declaring it. But we may need constructor for building the object. Through the explicit keyword we can prevent unwanted conversions that may be done using the constructor.

#include<iostream.h> class complex { private: float real,imag; public: complex() { real=imag=0.0; } explicit complex(float r, float i = 0.0) { real = r; imag = i; } complex operator+(complex c) { complex t; t.real=real+c.real; t.imag=imag+c.imag; return t; }

void display() { cout << endl << "real " << real << ", imag " << imag; } }; void main() { complex c1(1.5,3.5); c2 = c1 + 1.25; c2.display(); }
In the statement: c2=c1+1.25 The compiler would find that here the overloaded operator +() function should get called. When it finds that there is a wrong type on the right hand side of + it would look for a conversion function which can convert float to complex. The two argument constructor can meet this requirement. Hence the compiler would call it. This is an implicit conversion and can be prevented by declaring the constructor as explicit.

49) How a function pointer may be used to access a member function? Prototype of a function pointer of a member function of a class is

<function return> (<class name>::*<function pointer variable name>) (<function arguments>); Example: class class1 { void function(void) { } }; void main() { void (class1::*funct_ptr)(void); class1 c1; funct_ptr = c1.function; (c1.*funct_ptr)(); }

Warning: Call-time pass-by-reference has been deprecated in /home/content/43/10599843/html/vote.inc on line 13 Warning: Call-time pass-by-reference has been deprecated in /home/content/43/10599843/html/vote.inc on line 19 Warning: Call-time pass-by-reference has been deprecated in /home/content/43/10599843/html/vote.inc on line 75 50) What is object slicing?

Virtual functions ensure that the code that manipulates objects of the base type can without change manipulate derived type objects as well. Virtual functions should however always be called using either a pointer or a reference. If we try to do so using an object a phenomenon called object slicing takes place.

class base { public: virtual void funct1(void); }; class derived : public derived { public: virtual void funct1(void); virtual void funct2(void); }; void main() { base b; derived d; b = d; b.funct1(); //calls base::funct1() d.funct1(); //calls derived::funct1() }

51) What is ctor and what is the sequence of constructor calls? The sequence of constructor called is:

Base constructor | Derived constructor


Base constructor is called before the Derived constructor because derived constructor is yet to be built from the base class when the base constructor is invoked. 52) What is dtor and what is the sequence of destructor calls? The sequence of destructor is:

Derived destructor | Base destructor


For destructor, it is called from the most derived destructor down to the base destructor. 53) Why is virtual destructor important in inheritance? Virtual destructor in base class ensures that the destructor of derived class will be called when using base pointer to the object. Suppose we have a base class and a derived class

class base { public: base() { cout << "base construction";

} ~base() { cout << "base destruction"; } }; class derived : public base { char *name; public : derived () { cout << "derived construction"; name = new char[10]; cout << "mem allocated for name"; } ~ derived () { cout << "derived destruction"; delete [] name; cout << "mem de-allocated for name"; } }; void main() { base *b = new derived(); delete b; }
output:

base construction derived construction mem allocated for name base destruction
Here derived destruction is missing. Thus derived destructor is not getting called by compiler as it is early/compile time bind. As the type of the object is base, only base destructor is getting called. This also leads to memory leak as string member name is not getting de-allocated. To ensure proper destructor sequence call we must make the base destructor virtual. This ensures dynamic/runtime binding of the destructor through vtable mechanism After modifying the prototype ~base() to virtual ~base() the sequence will be as expected as below.

class base { public: base() { cout << "base construction"; } virtual ~base() { cout << "base destruction"; } };

Output after this change: base construction derived construction mem allocated for name derived destruction mem de-allocated for name base destruction
Similarly in future if we need to inherit child_derived from derived, we must make the destructor i.e. ~derived() as virtual. Thus it is a good practice to make destructor always virtual. This ensures proper calling sequence of destructors as it gets inherited down in the child classes. A good C++ editor always takes care of this. VC++ editor always makes destructor as virtual when it is created using wizard or template.

54) How can I print the type name of a variable? C++ Run Time Type Information Support also called RTTI. typeid() is a utility operator using which we can print the data type of the object during run time.

syntax: typeid().name()
The functions returns the type of the object as a string.

#include<iostream.h> #include<typeinfo.h> class mybase { }; class myclass : public mybase { }; myclass m1; void main() { mybase *b1 = new myclass(); cout << "object m1 is of type " << typeid(b1).name(); }
Output: object m1 is of type myclass 55) What is dynamic casting? C++ gives us the flexibility to check the type of object pointer at runtime by the keyword dynamic_cast. Example:

void main() { base * b; myclass m, *mp; b = &m; if(mp = dynamic_cast<myclass *>(b)) { cout << " b is type of myclass"; } else

{ cout << " b is not a type of myclass"; } }

56) What is static casting? A static cast is used for conversions that are well defined like: 1. cast less conversions, 2. down conversion, 3. conversions from void pointer, 4. implicit type conversion, Example:

l = static_cast<long>(i); i = static_cast<int>(l);

57) What is the difference between dynamic and static casting? Dynamic cast gives us the flexibility to check the type of object pointer at runtime. Example:

void main() { base * b; myclass m, *mp; b = &m; if(mp = dynamic_cast<myclass *>(b)) { cout << " b is type of myclass"; } else { cout << " b is not a type of myclass"; } }
A static cast is used for conversions that are well defined like: 1. 2. 3. 4. cast less conversions, down conversion, conversions from void pointer, implicit type conversion,

58) What is const casting? const cast is used to convert a constant variable a pointer pointing to a non constant variable.

const int c = 0; int *i_ptr ; i_ptr = const_cast<int *>(&c);

59) What is reinterpret casting?

Re-interpret cast can convert from an integer to pointer and vise versa.

int a = 0x65000; int *i_ptr = reinterpret_cast<int *>(a); a = reinterpret_cast<int >( i_ptr);

60) What is the difference between static casting and reinterpret casting? A static cast is used for conversions that are well defined like: 1. cast less conversions, 2. down conversion, 3. conversions from void pointer, 4. implicit type conversion, Re-interpret cast can convert from an integer to pointer and vise versa.

int a = 0x65000; int *i_ptr = reinterpret_cast<int *>(a); a = reinterpret_cast<int >( i_ptr);

61) What is template class? Template function is a type of function which only describes the procedure or statements of the function, i.e. what the function will do, but do not specify the data type of arguments. Thus a template class is a basic skeleton.

#include template T swap(T &a, T &b) { T temp; temp = a; a = b; b = temp; } void main() { int i = 10, j = 20; swap(i, j); cout << "Values i, j " << i << ", " << j; float a = 3.14, b = -6.28; swap(a, b); cout << "Values a, b " << a << ", " << b; }
From the above code, it is clear that if template was not used then individual functions have to be used to carry out swap of every data type used. Template class: Considering a class queue which adds elements to the rear and removes element from the front of an array.

#include const int MAX = 10; template class queue

{ private: T que[MAX]; int top; public: };

62) How does template differ from macro? Differences are: Macro cannot check the data type of arguments, If parameters of any macro are given with operators ++ and -- with it and the macro used this argument more than one times then the increment or decrement of the original variable will that much times. 3. Macros are expanded by the preprocessor and then compilation takes place. Compiler will refer error messages in expanded macro or the line where macro has been called. Example: 1. 2.

Case 1: template T swap(T &a, T &b) int a = 10; float b = 12.2f; We can never give swap(a, b); as a and b are of different type. Case 2: Extern int current_user; Extern int next_user; #define set_userid(x)\ current_user = x; \ next_user = x + 1; Int user = 10; current_user = x++; next_user = x++ + 1; current_user = 10; next_user = 12; user = 12; Case 3: Line:1:#define set_userid(x)\ Line:2:current_user = x \ Line:3:next_user = x + 1; Line:4:void main() Line:5:{ Line:6: int user = 10; Line:7: set_userid(user); Line:7:} main.c(7):error C2146: syntax error : missing ';' before identifier 'next_user' Line 2 has the original compilation error
Warning: Call-time pass-by-reference has been deprecated in /home/content/43/10599843/html/vote.inc on line 13 Warning: Call-time pass-by-reference has been deprecated in

/home/content/43/10599843/html/vote.inc on line 19 Warning: Call-time pass-by-reference has been deprecated in /home/content/43/10599843/html/vote.inc on line 75

Anda mungkin juga menyukai