Self-test 4:
Inheritance and Virtual Function

  1. The inheritance mechanism provides a means of deriving:

    1. a new class from an existing class.
    2. a new operator from an existing operator.
    3. a new set of memory allocation functions from the built-in ones.
    4. All of the above.
    Solution
    A is correct. Inheritance is a means of reusing code effectively. To derive a new operator from an existing operator or to derive a new set of memory allocation functions from the built-in ones is called operator overloading.

  2. The ___________ member function is declared in the base class but is redefined in the derived class to override the one in the base class.

    1. class
    2. overloaded
    3. virtual
    4. operator
    Solution
    C is correct. Redefining virtual functions is called overriding as opposed to overloading.

  3. State whether each of the following is true or false. If false, explain why.

    1. Base class constructors are not inherited by derived class.
    2. A has-a relationship is implemented via public inheritance.
    3. Inheritance encourages the reuse of proven high-quality software.
    4. When a derived-class object is destroyed, the destructors are called in the reverse order of the constructors.
    Solution
    A) True. B) False. A has-a relationship is implemented via composition. A is-a relationship is implemented via public inheritance. C) True. D) True.

  4. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class P {
      public:
       void print()  { cout <<" Inside P"; }
    };
    
    class Q : public P {
      public:
       void print() { cout <<" Inside Q"; }
    };
    
    class R: public Q { };
    
    int main(void)
    {
      R r;
      r.print();
      return 0;
    }
    
    1. Inside P
    2. Inside Q
    3. Nothing since class R doesn't define the print( ) function
    4. Compilation error: Ambiguous call to print( )
    Solution
    B is correct. The print function is not present in class R. So it is looked up in the inheritance hierarchy. print() is present in both classes P and Q, which of them should be called? The idea is, if there is multilevel inheritance, then function is linearly searched up in the inheritance hierarchy until a matching function is found.

  5. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class Base
    {
      public:
        void show() { cout<<" In Base "; }
    };
    
    class Derived: public Base
    {
      public:
        int x;
        void show() { cout<<"In Derived "; }
        Derived() : x(10) { }
    };
    
    int main(void)
    {
        Base *bp, b;
        Derived d;
        bp = &d;
        bp->show();
        cout << bp->x;
        return 0;
    }
    
    1. Compilation error for the line " bp->show()"
    2. Compilation error for the line " cout << bp->x"
    3. In Base 10
    4. In Derived 10
    Solution
    B is correct. A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer.

  6. Use of virtual functions implies:

    1. overloading.
    2. static binding.
    3. dynamic binding.
    Solution
    C is correct. Generally, virtual functions are mainly used when we need to do dynamic binding.

  7. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class Base
    {
      public:
        virtual void show() { cout<<" In Base\n"; }
    };
    
    class Derived: public Base
    {
      public:
        void show() { cout<<"In Derived\n"; }
    };
    
    int main(void)
    {
        Base *bp = new Derived;
        bp->show();
    
        Base &br = *bp;
        br.show();
    
        return 0;
    }
    
    1. In Base
      In Base
    2. In Base
      In Derived
    3. In Derived
      In Derived
    4. In Derived
      In Base
    Solution
    C is correct. Since show( ) is a virtual function in the base class, it is also virtual in the derived class. It is called according to the type of object being referenced or pointed, rather than the type of pointer or reference.

  8. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class Base
    {
      public:
        virtual void show() = 0;
    };
    
    int main(void)
    {
        Base b;
        Base *bp;
        return 0;
    }
    
    1. There are compilation errors in lines "Base b;" and "Base bp;"
    2. There is compilation error in line "Base b;
    3. There is compilation error in line "Base bp;"
    4. No compilation error
    Solution
    B is correct. Since Base has a pure virtual function, it becomes an abstract class and an instance of it cannot be created. So there is an error in line "Base b". Note that there is no error in line "Base *bp;". We can have pointers or references of abstract classes.

  9. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class A
    {
      public:
        virtual void fun() { cout << "A::fun() "; }
    };
    
    class B: public A
    {
      public:
       void fun() { cout << "B::fun() "; }
    };
    
    class C: public B
    {
      public:
       void fun() { cout << "C::fun() "; }
    };
    
    int main()
    {
        B *bp = new C;
        bp->fun();
        return 0;
    }
    
    1. A::fun()
    2. B::fun()
    3. C::fun()
    Solution
    C is correct. The important thing to note here is B::fun() is virtual even if we have not uses virtual keyword with it. When a class has a virtual function, functions with the same signature in all its descendant classes automatically become virtual. We don't need to use the virtual keyword in declaration of fun( ) in B and C. They are anyways virtual, but it is a good practice to add the virtual keyword to those functions in the derived classes.

  10. What is the output of following program?

    #include<iostream>
    using namespace std;
    
    class Base
    {
      public:
        virtual void show() { cout << "In Base\n"; }
    };
    
    class Derived: public Base
    {
      public:
        virtual void show() { cout << "In Derived\n"; }
    };
    
    int main(void)
    {
        Base *bp = new Derived;
        bp->Base::show();  // Note the use of scope resolution here
        return 0;
    }
    
    1. In Base
    2. In Derived
    3. Compilation error
    4. Runtime Error
    Solution
    A is correct. A base class function can be accessed with scope resolution operator even if the function is virtual.