OOPS-Unit 3

Add to Favourites
Post to:

UNIT III-INHERITANCE AND POLYMORPHISM Objectives: · To introduce Inheritance in C++ and to explain its importance. · To make understand the different types of inheritance. · To define typing conversion and visibility · To explain virtual functions · To know about function overloading. · To provide an overview about operator overloading. Topics Covered: · Introduction · Inheritance · A derived class · Types of Inheritance · Typing conversion and visibility · Virtual functions · Abstract base class · Function overloading · Operator Overloading. S.Sathish Lec/IT OOPS S.SathishIntroduction Inheritance is probably the most powerful feature of object-oriented programming, after classes themselves. Inheritance is the process of creating new classes, called derived classes, from existing or base classes. The derived class inherits all the capabilities of the base class but can add embellishments and refinements of its own. The base class is unchanged by this process Inheritance is an essential part of OOP. Its big payoff is that it permits code reusability. Once a base class is written and debugged, it need not be touched again, but, using inheritance, can nevertheless be adapted to work in different situations. Reusing existing code saves time and money and increases a program’s reliability. Inheritance can also help in the original conceptualization of a programming problem, and in the overall design of the program. An important result of reusability is the ease of distributing class libraries. A programmer can use a class created by another person or company, and, without modifying it, derive other classes from it that are suited to particular situations. Operator overloading is one of the most exciting features of object-oriented programming. It can transform complex, obscure program listings into intuitively obvious ones. For example, statements like d3.addobjects(d1, d2); or the similar but equally obscure d3 = d1.addobjects(d2); can be changed to the much more readable d3 = d1 + d2; The rather forbidding term operator overloading refers to giving the normal C++ operators, such as +, *, <=, and +=, additional meanings when they are applied to user-defined data types. Normally a = b + c; works only with basic types such as int and float, and attempting to apply it when a, b, and c are objects of a user-defined class will cause complaints from the compiler. However, using overloading, you can make this statement legal even when a, b, and c are user-defined types. In effect, operator overloading gives you the opportunity to redefine the C++ language. If you find yourself limited by the way the C++ operators work, you can change them to do whatever you want. By using classes to create new kinds of variables, and operator OOPS S.Sathishoverloading to create new definitions for operators, you can extend C++ to be, in many ways, a new language of your own design. Another kind of operation, data type conversion, is closely connected with operator overloading. C++ handles the conversion of simple types, such as int and float, automatically; but conversions involving user-defined types require some work on the programmer’s part. We’ll look at data conversions in the second part of this chapter. Overloaded operators are not all beer and skittles. We’ll discuss some of the dangers of their use at the end of the chapter. 3.1. INHERITANCE · C++ strongly support the reusability, that is one class has been written and tested already it can be adapted or used to create a new class. · The reusable property will reduce the debugging time · The time overhead and cost overhead will be reduced. · Thus, the reusability mechanism is apply to the Inheritance Definition The mechanism of deriving the new class from an old one is called inheritance. The old class is called as base class and the new class is called as derived class. Types of Inheritance i . Single inheritance ii. Multiple inheritance iii. Multilevel inheritance iv. Hierarchical inheritance v. Hybrid inheritance i. Single Inheritance The new class can be derived from only one base class is called single inheritance. This can be represented Fig: Single Inheritance OOPS S.SathishDefining derived classes: A derived class is defined by specifying its relationship with the base class in addition to its own details. The general format is class derived classname: visibility mode baseclassname {. . . . . //body of derived class }; Visibility mode is optional; it may be either private or public. The default visibility mode is private. Eg: class ABC : private xyz { //body of ABC }; class ABC : public xyz{ //body of ABC }; class ABC : xyz //private derivation by default { //body of ABC }; Example program #include class A { protected: int data; public: void getdata(int x) { data1 = x; }}; class B: public A { private: public: void setdata(int y) { data2 = y;} void display( ) { cout<<”data1”< class student {protected: int rollno: OOPS S.Sathishpublic: void getroll(int x) {rollno = x; }}; void test: public student {protected: float sub1, sub2; public: void getmart(int y, int z) {sub1 = y; sub2= z; }}; void result : public test {float total; public: void display( ) {total = sub1 + sub2; cout< class A {protected: int rollno; public: void getroll(int x) {rollno=x; }}; class B {protected: int sub1,sub2; public: void getmark(int y,int z)\ {sub1=y; sub2=z; }}; class C : public A, public B {int total; public: void display() {total=sub1+sub2; cout<<”roll no:”< class student {protected: int rollno; public: void getroll (int x) {rollno = x; }}; class test: public student {protected: int sub1, sub2’ public: void getmark (int y, int z) {sub1 = y; sub2 = z; }}; class sports {protected: int score; public: void getscore (int a ) {score=a; }}; class result: public test, public sports {int total; public: void display() { OOPS S.Sathishtotal= sub1+sub2+score; cout<<”rollno:”< Class A { OOPS S.Sathishpublic: A ( ) {cout<<” Have a nice day”; }}; Class B: public A {public: }; void main( ) {B s; }If the derived class object is created it will check the base class first and execute the corresponding default constructor. Case 3: Constructor only in the derived class #include Class A {public: }; Class B: public A {public: A ( ) {cout<<”Have a nice day”; }}; void main( ) {B s; } If the derived class object is created, it will check the base class first if there is no constructor in the base class, it will skip the base class & run the constructor in the derived class. Case 4: Constructor in both base and derived class: #include Class A {public: A ( ) {cout<<”Have a nice day”; }}; OOPS S.Sathishclass B: public A {public: B ( ) {cout<<”Welcome”; }}; void main( ) {B s; }If the derived class object is created it will check the base class & execute thecorresponding constructor and then it will execute the corresponding derived classconstructor. Case 5: Multiple constructor in base class single constructor in derived class #include Class A {public: A ( ) {cout<<”Have a nice day”; }A (int a) {cout<<”Welcome”; }}; class B: public A {public: B (int a) {cout<<”Good Morning”; }}; void main( ) {B s(10); }In multiple constructors first the base class default constructor will be executed, if the parameters constructor is not explicitly called in the derived class means it will skip the parameter Constructor and will execute the corresponding derived class constructor. OOPS S.SathishCase 6: Constructor in base and derived class without default constructor: #include class A {public: A (int a) {cout<<”Welcome”; }}; class B: public A {public: B (int a): A (a) {cout<<”Good Morning”; }}; void main( ) {B s(10); }Output: Welcome Good Morning Base class constructor is explicitly called in derived class (i.e.) B(int a): A(a); whenever derived class object is created it will execute the base class constructor first and then derived class constructor. Virtual Base Classes An element of ambiguity can be introduced into a C++ program when multiple base classes are inherited. For example, consider this incorrect program: //This program contains an error and will not compile. #include using namespace std; class base { public: int i; }; //derived1 inherits base. class derived1 : public base { public: int j; }; //derived2 inherits base. class derived2 : public base { OOPS S.Sathishpublic: int k; }; /* derived3 inherits both derived1 and derived2. This means that there are two copies of base in derived3! */class derived3 : public derived1, public derived2 { public: int sum; }; int main() {derived3 ob; ob.i = 10; //this is ambiguous, which i??? ob.j = 20; ob.k = 30; //i ambiguous here, too ob.sum = ob.i + ob.j + ob.k; //also ambiguous, which i? cout << ob.i << " "; cout << ob.j << " " << ob.k << " "; cout << ob.sum; return 0; } As the comments in the program indicate, both derived1 and derived2 inherit base. However, derived3 inherits both derived1 and derived2. This means that there are two copies of base present in an object of type derived3. Therefore, in an expression like ob.i = 10; which i is being referred to, the one in derived1 or the one in derived2? Because there are two copies of base present in object ob, there are two ob.is! As you can see, the statement is inherently ambiguous. There are two ways to remedy the preceding program. The first is to apply the scope resolution operator to i and manually select one i. For example, this version of the program does compile and run as expected: //This program uses explicit scope resolution to select i. #include using namespace std; class base { public: int i; }; //derived1 inherits base. class derived1 : public base { public: int j; }; OOPS S.Sathish//derived2 inherits base. class derived2 : public base { public: int k; }; /* derived3 inherits both derived1 and derived2. This means that there are two copies of base in derived3! */class derived3 : public derived1, public derived2 { public: int sum; }; int main() {derived3 ob; ob.derived1::i = 10; //scope resolved, use derived1's i ob.j = 20; ob.k = 30; //scope resolved ob.sum = ob.derived1::i + ob.j + ob.k; //also resolved here cout << ob.derived1::i << " "; cout << ob.j << " " << ob.k << " "; cout << ob.sum; return 0; }As you can see, because the :: was applied, the program has manually selected derived1's version of base. However, this solution raises a deeper issue: What if only one copy of base is actually required? Is there some way to prevent two copies from being included in derived3? The answer, as you probably have guessed, is yes. This solution is achieved using virtual base classes. When two or more objects are derived from a common base class, you can prevent multiple copies of the base class from being present in an object derived from those objects by declaring the base class as virtual when it is inherited. You accomplish this by preceding the base class' name with the keyword virtual when it is inherited. For example, here is another version of the example program in which derived3 contains only one copy of base: //This program uses virtual base classes. #include using namespace std; class base { public: int i; }; //derived1 inherits base as virtual. class derived1 : virtual public base { public: int j; OOPS S.Sathish}; //derived2 inherits base as virtual. class derived2 : virtual public base { public: int k; }; /* derived3 inherits both derived1 and derived2. This time, there is only one copy of base class. */class derived3 : public derived1, public derived2 { public: int sum; }; int main() {derived3 ob; ob.i = 10; //now unambiguous ob.j = 20; ob.k = 30; //unambiguous ob.sum = ob.i + ob.j + ob.k; //unambiguous cout << ob.i << " "; cout << ob.j << " " << ob.k << " "; cout << ob.sum; return 0; }The keyword virtual precedes the rest of the inherited class specification. Now that both derived1 and derived2 have inherited base as virtual, any multiple inheritance involving them will cause only one copy of base to be present. Therefore, in derived3, there is only one copy of base and ob.i = 10 is perfectly valid and unambiguous. One further point to keep in mind: Even though both derived1 and derived2 specify base as virtual, base is still present in objects of either type. For example, the following sequence is perfectly valid: //define a class of type derived1 derived1 myclass; myclass.i = 88; The only difference between a normal base class and a virtual one is what occurs when an object inherits the base more than once. If virtual base classes are used, then only one base class is present in the object. Otherwise, multiple copies will be found. Polymorphism is supported by C++ both at compile time and at run time. Compile-time polymorphism is achieved by overloading functions and operators. Run-time polymorphism is accomplished by using inheritance and virtual functions, 3.3. Virtual Functions A virtual function is a member function that is declared within a base class and redefined by a derived class. To create a virtual function, precede the function's declaration in the base class with the keyword virtual. When a class containing a virtual function is inherited, the derived OOPS S.Sathishclass redefines the virtual function to fit its own needs. In essence, virtual functions implement the "one interface, multiple methods" philosophy that underlies polymorphism. The virtual function within the base class defines the form of the interface to that function. Each redefinition of the virtual function by a derived class implements its operation as it relates specifically to the derived class. That is, the redefinition creates a specific method. When accessed "normally," virtual functions behave just like any other type of class member function. However, what makes virtual functions important and capable of supporting runtiim polymorphism is how they behave when accessed via a pointer. As discussed in Chapter 13, a base-class pointer can be used to point to an object of any class derived from that base. When a base pointer points to a derived object that contains a virtual function, C++ determines which version of that function to call based upon the type of object pointed to by the pointer. And this determination is made at runtime. Thus, when different objects are pointed to, different versions of the virtual function are executed. The same effect applies to base-class references. To begin, examine this short example: #include using namespace std; class base { public: virtual void vfunc() { cout << "This is base's vfunc().\n"; }}; class derived1 : public base { public: void vfunc() { cout << "This is derived1's vfunc().\n"; }}; class derived2 : public base { public: void vfunc() { cout << "This is derived2's vfunc().\n"; }}; int main() {base *p, b; derived1 d1; derived2 d2; //point to base p = &b; p->vfunc(); //access base's vfunc() //point to derived1 p = &d1; p->vfunc(); //access derived1's vfunc() //point to derived2 OOPS S.Sathishp = &d2; p->vfunc(); //access derived2's vfunc() return 0; }This program displays the following: This is base's vfunc(). This is derived1's vfunc(). This is derived2's vfunc(). As the program illustrates, inside base, the virtual function vfunc() is declared. Notice that the keyword virtual precedes the rest of the function declaration. When vfunc() is redefined by derived1 and derived2, the keyword virtual is not needed. (However, it is not an error to include it when redefining a virtual function inside a derived class; it's just not needed.) class definition, vfunc() is redefined relative to that class. Inside main(), four variables are declared: Name Type p base class pointer b object of base d1 object of derived1 d2 object of derived2 Next, p is assigned the address of b, and vfunc() is called via p. Since p is pointing to an object of type base, that version of vfunc() is executed. Next, p is set to the address of d1, and again vfunc() is called by using p. This time p points to an object of type derived1. This causes derived1::vfunc() to be executed. Finally, p is assigned the address of d2, and p−>vfunc() causes the version of vfunc() redefined inside derived2 to be executed. The key point here is that the kind of object to which p points determines which version of vfunc() is executed. Further, this determination is made at run time, and this process forms the basis for run-time polymorphism. Although you can call a virtual function in the "normal" manner by using an object's name and the dot operator, it is only when access is through a base-class pointer (or reference) that run-time polymorphism is achieved. For example, assuming the preceding example, this is syntactically valid: 3.4. Pure Virtual Functions As the examples in the preceding section illustrate, when a virtual function is not redefined by a derived class, the version defined in the base class will be used. However, in many situations there can be no meaningful definition of a virtual function within a base class. For example, a base class may not be able to define an object sufficiently to allow a base-class virtual function to be created. Further, in some situations you will want to ensure that all derived classes override a virtual function. To handle these two cases, C++ supports the pure virtual function. A pure virtual function is a virtual function that has no definition within the base class. To declare a pure virtual function, use this general form: virtual type func-name(parameter-list) = 0; OOPS S.SathishWhen a virtual function is made pure, any derived class must provide its own definition. If the derived class fails to override the pure virtual function, a compile-time error will result. The following program contains a simple example of a pure virtual function. The base class, number, contains an integer called val, the function setval() , and the pure virtual function show() . The derived classes hextype, dectype, and octtype inherit number and redefine show() so that it outputs the value of val in each respective number base (that is, hexadecimal, decimal, or octal). #include using namespace std; class number { protected: int val; public: void setval(int i) { val = i; } //show() is a pure virtual function virtual void show() = 0; }; class hextype : public number { public: void show() { cout << hex << val << "\n"; }}; class dectype : public number { public: void show() { cout << val << "\n"; }}; class octtype : public number { public: void show() { cout << oct << val << "\n"; } }; int main() { dectype d; hextype h; octtype o; d.setval(20); d.show(); //displays 20 -decimal h.setval(20); h.show(); //displays 14 -hexadecimal o.setval(20); o.show(); //displays 24 -octal return 0; }OOPS S.SathishAlthough this example is quite simple, it illustrates how a base class may not be able to meaningfully define a virtual function. In this case, number simply provides the common interface for the derived types to use. There is no reason to define show() inside number since the base of the number is undefined. Of course, you can always create a placeholder definition of a virtual function. However, making show() pure also ensures that all derived classes will indeed redefine it to meet their own needs. Keep in mind that when a virtual function is declared as pure, all derived classes must override it. If a derived class fails to do this, a compile-time error will result. 3.5. Abstract Classes A class that contains at least one pure virtual function is said to be abstract. Because an abstract class contains one or more functions for which there is no definition (that is, a pure virtual function), no objects of an abstract class may be created. Instead, an abstract class constitutes an incomplete type that is used as a foundation for derived classes. Although you cannot create objects of an abstract class, you can create pointers and references to an abstract class. This allows abstract classes to support run-time polymorphism, which relies upon base-class pointers and references to select the proper virtual function. 3.5.1. Using Virtual Functions One of the central aspects of object-oriented programming is the principle of "one interface, multiple methods." This means that a general class of actions can be defined, the interface to which is constant, with each derivation defining its own specific operations. In concrete C++ terms, a base class can be used to define the nature of the interface to a general class. Each derived class then implements the specific operations as they relate to the type of data used by the derived type. One of the most powerful and flexible ways to implement the "one interface, multiple methods" approach is to use virtual functions, abstract classes, and run-time polymorphism. Using these features, you create a class hierarchy that moves from general to specific (base to derived). Following this philosophy, you define all common features and interfaces in a base class. In cases where certain actions can be implemented only by the derived class, use a virtual function. In essence, in the base class you create and define everything you can that relates to the general case. The derived class fills in the specific details. Following is a simple example that illustrates the value of the "one interface, multiple methods" philosophy. A class hierarchy is created that performs conversions from one system of units to another. (For example, liters to gallons.) The base class convert declares two variables, val1 and val2, which hold the initial and converted values, respectively. It also defines the functions getinit() and getconv() , which return the initial value and the converted value. These elements of convert are fixed and applicable to all derived classes that will inherit convert. However, the function that will actually perform the conversion, compute() , is a pure virtual function that must be defined by the classes derived from convert. The specific nature of compute() will be determined by what type of conversion is taking place. //Virtual function practical example. #include using namespace std; class convert { OOPS S.Sathishprotected: double val1; //initial value double val2; //converted value public: convert(double i) { val1 = i; }double getconv() { return val2; } double getinit() { return val1; } virtual void compute() = 0; }; //Liters to gallons. class l_to_g : public convert { public: l_to_g(double i) : convert(i) { } void compute() { val2 = val1 /3.7854; }}; //Fahrenheit to Celsius class f_to_c : public convert { public: f_to_c(double i) : convert(i) { } void compute() { val2 = (val1-32) /1.8; }}; int main() {convert *p; //pointer to base class l_to_g lgob(4); f_to_c fcob(70); //use virtual function mechanism to convert p = &lgob; cout << p->getinit() << " liters is "; p->compute(); cout << p->getconv() << " gallons\n"; //l_to_g p = &fcob; cout << p->getinit() << " in Fahrenheit is "; p->compute(); cout << p->getconv() << " Celsius\n"; //f_to_c return 0; } 3.6.Operator Overloading An operator function defines the operations that the overloaded operator will perform relative to the class upon which it will work. An operator function is created using the keyword operator. Creating a Member Operator Function OOPS S.SathishA member operator function takes this general form: ret-type class-name::operator#(arg-list) {//operations } The # is a placeholder. When you create an operator function, substitute the operator for the #. For example, if you are overloading the /operator, use operator/. When you are overloading a unary operator, arg-list will be empty. When we are overloading binary operators, arg-list will contain one parameter. Example: #include using namespace std; class loc { int longitude, latitude; public: loc() {} loc(int lg, int lt) { longitude = lg; latitude = lt; }void show() { cout << longitude << " "; cout << latitude << "\n"; }loc operator+(loc op2); }; //Overload + for loc. loc loc::operator+(loc op2) {loc temp; temp.longitude = op2.longitude + longitude; temp.latitude = op2.latitude + latitude; return temp; }int main() {loc ob1(10, 20), ob2( 5, 30); ob1.show(); //displays 10 20 ob2.show(); //displays 5 30 ob1 = ob1 + ob2; ob1.show(); //displays 15 50 return 0; } Here the operator+() function returned some other type, this expression would not have been valid: ob1 = ob1 + ob2; In order for the sum of ob1 and ob2 to be assigned to ob1, the outcome of that operation must be an object of type loc. OOPS S.Sathish3.6.1. Operator Overloading Using a Friend Function Since a friend function is not a member of the class, it does not have a this pointer. Therefore, an overloaded friend operator function is passed the operands explicitly. This means that a friend function that overloads a binary operator has two parameters, and a friend function that overloads a unary operator has one parameter. When overloading a binary operator using a friend function, the left operand is passed in the first parameter and the right operand is passed in the second parameter. In this program, the operator+() function is made into a friend: #include using namespace std; class loc { int longitude, latitude; public: loc() {} //needed to construct temporaries loc(int lg, int lt) { longitude = lg; latitude = lt; }void show() { cout << longitude << " "; cout << latitude << "\n"; }friend loc operator+(loc op1, loc op2); //now a friend loc operator-(loc op2); loc operator=(loc op2); loc operator++(); }; //Now, + is overloaded using friend function. loc operator+(loc op1, loc op2) { loc temp; temp.longitude = op1.longitude + op2.longitude; temp.latitude = op1.latitude + op2.latitude; return temp; }//Overload -for loc. loc loc::operator-(loc op2) { loc temp; //notice order of operands temp.longitude = longitude -op2.longitude; temp.latitude = latitude -op2.latitude; OOPS S.Sathishreturn temp; }//Overload assignment for loc. loc loc::operator=(loc op2) { longitude = op2.longitude; latitude = op2.latitude; return *this; //i.e., return object that generated call }//Overload ++ for loc. loc loc::operator++() {longitude++; latitude++; return *this; }int main() {loc ob1(10, 20), ob2( 5, 30); ob1 = ob1 + ob2; ob1.show(); return 0; } There are some restrictions that apply to friend operator functions. First, you may not overload the =, ( ), [ ], or –> operators by using a friend function. Second, as explained in the next section, when overloading the increment or decrement operators, you will need to use a reference parameter when using a friend function. 3.6.2. Using a Friend to Overload ++ or – – If we want to use a friend function to overload the increment or decrement operators, you must pass the operand as a reference parameter. This is because friend functions do not have this pointers. #include using namespace std; class loc { int longitude, latitude; public: loc() {} loc(int lg, int lt) { longitude = lg; latitude = lt; }void show() { cout << longitude << " "; cout << latitude << "\n"; }loc operator=(loc op2); friend loc operator++(loc &op); friend loc operator--(loc &op); }; OOPS S.Sathish//Overload assignment for loc. loc loc::operator=(loc op2) { longitude = op2.longitude; latitude = op2.latitude; return *this; //i.e., return object that generated call }//Now a friend; use a reference parameter. loc operator++(loc &op) { op.longitude++; op.latitude++; return op; }//Make op--a friend; use reference. loc operator--(loc &op) { op.longitude--; op.latitude--; return op; } int main() {loc ob1(10, 20), ob2; ob1.show(); ++ob1; ob1.show(); //displays 11 21 ob2 = ++ob1; ob2.show(); //displays 12 22 --ob2; ob2.show(); //displays 11 21 return 0; } If we want to overload the postfix versions of the increment and decrement operators using a friend, simply specify a second, dummy integer parameter. For example, this shows the prototype for the friend, postfix version of the increment operator relative to loc. //friend, postfix version of ++ friend loc operator++(loc &op, int x); 1. What is meant by operator overloading? 2. Which operators can not be overloaded? 3.6.3. Overloading new and delete It is possible to overload new and delete. You might choose to do this if you want to use some special allocation method. For example, you may want allocation routines that automatically begin using a disk file as virtual memory when the heap has been exhausted. Whatever the reason, it is a very simple matter to overload these operators. The skeletons for the functions that overload new and delete are shown here: //Allocate an object. void *operator new(size_t size) OOPS S.Sathish{/* Perform allocation. Throw bad_alloc on failure. Constructor called automatically. */return pointer_to_memory; }//Delete an object. void operator delete(void *p) {/* Free memory pointed to by p. Destructor called automatically. */} The type size_t is a defined type capable of containing the largest single piece of memory that can be allocated. (size_t is essentially an unsigned integer.) The parameter size will contain the number of bytes needed to hold the object being allocated. This is the amount of memory that our version of new must allocate. The overloaded new function must return a pointer to the memory that it allocates, or throw a bad_alloc exception if an allocation error occurs. Beyond these constraints, the overloaded new function can do anything else you require. When you allocate an object using new (whether your own version or not), the object's constructor is automatically called. The delete function receives a pointer to the region of memory to be freed. It then releases the previously allocated memory back to the system. When an object is deleted, its destructor function is automatically called. Example #include #include #include using namespace std; class loc { int longitude, latitude; public: loc() {} loc(int lg, int lt) { longitude = lg; latitude = lt; }void show() { cout << longitude << " "; cout << latitude << "\n"; }void *operator new(size_t size); void operator delete(void *p); }; //new overloaded relative to loc. void *loc::operator new(size_t size) { void *p; cout << "In overloaded new.\n"; p = malloc(size); if(!p) { OOPS S.Sathishbad_alloc ba; throw ba; }return p; } //delete overloaded relative to loc. void loc::operator delete(void *p) {cout << "In overloaded delete.\n"; free(p); }int main() {loc *p1, *p2; try { p1 = new loc (10, 20); } catch (bad_alloc xa) { cout << "Allocation error for p1.\n"; return 1; }try { p2 = new loc (-10, -20); } catch (bad_alloc xa) { cout << "Allocation error for p2.\n"; return 1;; }p1->show(); p2->show(); delete p1; delete p2; return 0; } Output from this program is. In overloaded new. In overloaded new. 10 20 -10 -20 In overloaded delete. In overloaded delete. Assessment Question-1(Inheritance) 1. Inheritance is a way to a. make general classes into more specific classes. b. pass arguments to objects of classes. c. add features to existing classes without rewriting them. d. improve data hiding and encapsulation. 2. A “child” class is said to be _________ from a base class. OOPS S.Sathish3. Advantages of inheritance include a. providing class growth through natural selection. b. facilitating class libraries. c. avoiding the rewriting of code. d. providing a useful conceptual framework. 4. Write the first line of the specifier for a class Bosworth that is publicly derived from a class Alphonso. 5. True or false: Adding a derived class to a base class requires fundamental changes to the base class. 6. To be accessed from a member function of the derived class, data or functions in the base class must be public or _________. 7. If a base class contains a member function basefunc(), and a derived class does not contain a function with this name, can an object of the derived class access basefunc()? 8. Assume that the classes mentioned in Question 4 and the class Alphonso contain a member function called alfunc(). Write a statement that allows object BosworthObj of class Bosworth to access alfunc(). 9. True or false: If no constructors are specified for a derived class, objects of the derived class will use the constructors in the base class. 10. If a base class and a derived class each include a member function with the same name, which member function will be called by an object of the derived class, assuming the scope-resolution operator is not used? 11. Write a declarator for a no-argument constructor of the derived class Bosworth of Question 4 that calls a no-argument constructor in the base class Alphonso. 12. The scope-resolution operator usually a. limits the visibility of variables to a certain function. b. tells what base class a class is derived from. c. specifies a particular class. d. resolves ambiguities. 13. True or false: It is sometimes useful to specify a class from which no objects will ever be created. 14. Assume that there is a class Derv that is derived from a base class Base. Write the declarator for a derived-class constructor that takes one argument and passes this argument along to the constructor in the base class. 15. Assume a class Derv that is privately derived from class Base. An object of class Derv located in main() can access a. public members of Derv. b. protected members of Derv. c. private members of Derv. d. public members of Base. OOPS S.Sathishe. protected members of Base. f. private members of Base. 16. True or false: A class D can be derived from a class C, which is derived from a class B, which is derived from a class A. 17. A class hierarchy a. shows the same relationships as an organization chart. b. describes “has a” relationships. c. describes “is a kind of” relationships. d. shows the same relationships as a family tree. 18. Write the first line of a specifier for a class Tire that is derived from class Wheel and from class Rubber. 19. Assume a class Derv derived from a base class Base. Both classes contain a member function func() that takes no arguments. Write a statement to go in a member function of Derv that calls func() in the base class. 20. True or false: It is illegal to make objects of one class members of another class. 21. In the UML, inheritance is called _____________. 22. Aggregation is a. a stronger form of instantiation. b. a stronger form of generalization. c. a stronger form of composition. d. a “has a” relationship. 23. True or false: the arrow representing generalization points to the more specific class. 24. Composition is a ___________ form of ____________. Possible Questions Part-A 1. What is meant by inheritance? 2. What is meant by single inheritance? 3. What is multiple inheritances? 4. What is hierarchical inheritance? 5. What is multilevel inheritance? 6. What is hybrid inheritance? 7. What is meant by Abstract base class? 8. Write short notes on virtual base class. 9. What are Friend functions? Write the syntax 10. Write some properties of friend functions. 11. What are the virtual functions? 12. Write some of the basic rules for virtual functions 13. What are pure virtual functions? Write the syntax. 14. Which operators can not be overloaded? 15. What is meant by operator overloading? OOPS S.SathishPart-B 1. Discuss briefly on friend functions. 2. Describe how the following features are supported by C++. a. Inheritance. b. Concurrency. c. Genericity. 3. Write a program to read words and print in reverse order .Illustrate use of Keywords to dynamically allocate space for each of the strings that are read in. 4. What are the rules associated with virtual functions? 5. What are the different forms of inheritance supported in c++? Discuss on the visibility of base class members in privately and publicly inherited classes. 6. What are abstract classes? Give an example (with the program) to illustrate the use of abstract classes. 7. Explain operator overloading with an example. 8. How do you overload the operators ‘new’ and ‘delete’? Give a sample program to implement both. Answers to assessment Question-1(Inheritance) 1. a, c 2. derived 3. b, c, d 4. class Bosworth : public Alphonso 5. false 6. protected 7. yes (assuming basefunc is not private) 8. BosworthObj.alfunc(); 9. true 10. the one in the derived class 11. Bosworth() : Alphonso() { } 12. c, d 13. true 14. Derv(int arg) : Base(arg) 15. a 16. true 17. c 18. class Tire : public Wheel, public Rubber 19. Base::func(); 20. false 21. generalization 22. d 23. false 24. stronger, aggregation OOPS S.Sathish

Comments

Want to learn?

Sign up and browse through relevant courses.

Name:
Your Email:
Password:
Country:
Contact no:


Area code Number
Subjects you are interested in:
Word verification: (Enter the text as in image)


Sign Up Already a member? Sign In
I agree to WizIQ's User Agreement & Privacy Policy
8 Followers

Your Facebook Friends on WizIQ

Give live classes, create & sell online courses

Try it free Plans & Pricing

Connect