Chapters 9 to 11 (Inheritance, Operator overloading and streams)

Workshop Quiz (will try to make it interactive)


Q.) Complete the following tabulation on operator overloading by specifying the return type which one would normally use: 

Operator overloaded

Return type

+

 

::

 

=

 

<

 

+=

 

!

 

= =

 

-

 

? :

 

 


Q.) Which form (postfix/ prefix) of the unary operator ++ involve more overhead? Or are they just different in terms of representation alone? 

A.) When we say:

            x = ++y;

‘y’ is incremented and the value is assigned to ‘x’ (first increment and then obtain value).

Whereas in:

            x = y++;

the value of ‘y’ is first assigned to ‘x’ and then ‘y’ is incremented (so ‘x’ actually has the old value of ‘x’). Here we obtain the value first and then increment. To remember how they work all you need to do is take a look at how we use them; when we say ++y the ++ comes before the ‘y’. Thus we first increment and then obtain the value whereas in y++, we get ‘y’ first and then increment it (it’s just a memory aid since many new programmers tend to get confused with the 2 forms). 

Next let’s consider the following statement:

            y++++;            //Error

This is equivalent to: (y++)++;

Obviously y++ returns an integer, so why is it not permitted? That’s because the return type of the postfix operator is a constant (in this case a constant integer). Thus you can modify the returned value again.

Let’s consider the other statement:

            ++++y;            //no error

You wouldn’t get an error because the prefix operator returns a reference (rather than an object). 

Why the difference in return types?

In ++y, all that needs to be done is to increment the current value and return a reference to the same object. But in y++, we need to create a new object to store the old value of ‘y’, then increment ‘y’ and then return the new object (which is why postfix form means ‘get value and then increment’). 

Thus the postfix form would be less efficient than the prefix form since it involves an extra object.  

And the following fragment will work:

            i=5;

            ++++++i;

would end up incrementing ‘i’ 3 times (‘i’ would have a value of 8). The statement is equal to:

(++ ( ++ (++i) ) );

And the prefix form of ++ has associativity from right to left. This works because the prefix form of ++ returns a reference to the same object. But we wouldn’t want to use such a statement because it reduces readability (you will have to keep counting the number of +s each time you go through the code). 


Q.) Why doesn’t the following code compile? 

class employee
{
public:
            employee(int x)
            {}
};

class teacher:public employee
{
public:
            teacher( )
            {}
};
 

class librarian:public employee
{
public:
            librarian(int y):employee(y)
            {}
}; 

int main( )
{
            teacher f1;
            librarian m1(5);
            return 0;
}

 A.) When an object of type teacher is created, the compiler will try to call the default constructor of the base class (i.e. of the class employee). But employee doesn’t have a default constructor and thus the following code produces the error:

public:
            teacher( )
            {}

The class librarian is fine since here we are explicitly calling the parameterized constructor for employee (here the compiler won’t call the default constructor). 


Q.) What does “is a kind of” relationship in C++?

A.) This term is just another name for the “is a” relation (public inheritance). 


Q.) Why would a programmer place a constructor in the protected region of a class? Or is this an error? 

class base
{
protected:
            base( )
            {
                        cout<<"base constructor";
            }
};

class derived:public base
{};

int main( )
{
            derived d1;
            return 0;
}
 

A.) This is perfectly legal. By placing the base constructor in the protected region, a user cannot instantiate an object of type ‘base’. The following code would cause a compiler error:

            base b1;           //error-cannot access protected constructor 

But any class derived from ‘base’ will be able to invoke the base class constructor (as done in the question). The output of the program will be:

            base constructor 


Q.) Is it legal to place the constructor in the private region of a class? 

class base
{
private:
            base( )
            {
                        cout<<"base constructor";
            }
};
 

A.) This would serve no useful purpose because now even a derived class cannot access the constructor of ‘base’ (because private members are inaccessible by the derived class irrespective of how you inherit the base class).

And as discussed in the earlier question, neither can we directly instantiate an object of type ‘base’ (this would lead to a compiler error). 


Q.) What does the following code do? What is the purpose of the keyword ‘using’? 

class base
{
protected:
            void b_func( )
            {
                        cout<<endl<<"Base function";
            }
};

class derived:private base
{
public:
            using base::b_func;
};
 

A.) Any object of type ‘derived’ can now invoke the function b_func( ) just as if b_func ( ) were a member function of class ‘derived’. If the code:

public:

            using base::b_func;

was not written then the following would be illegal:

            int main( )
            {
            derived d1;
            d1.b_func( );    //error- cannot access protected member
            return 0;
            } 

The general syntax for ‘using’ in such a scenario is:

            using base-class-name:: base-class-function-name;

We shouldn’t specify the parameters. i.e. the following is wrong:

            using base::b_func( );                //error


Q.) Why don’t we have a virtual constructor? 

            The concept of ‘virtual’ functions is used since the type of object is not known at compile-time. The calling object is determined at run-time instead. But a constructor is used to create/ construct an object and this is almost certainly known while compiling. We can construct something only if we know what we are going to create. Thus C++ doesn’t provide for virtual constructors (but there are some ways of obtaining the effect of virtual constructors- generally not required). 


Q.) What is wrong with the following code (it crashes sometimes and sometimes it gives weird results): 

class myarray
{
public:
            int *ptr;
            myarray(int val)
            {
                        ptr= new int;
                        *ptr=val;
            }

            ~myarray( )
            {           delete ptr;                      } 

            void display( )
            {           cout<<endl<<*ptr;          }

};

int main( )
{
            myarray arr1(10);
            cout<<endl<<"arr1 declared outside block is:";
            arr1.display( );
            {
                        myarray arr2(50);
                        cout<<endl<<"arr2 is within inner block:";
                        arr2.display( );
                        arr2=arr1;
                        cout<<endl<<"arr2 after assignment is:";
                        arr2.display( );
            }

            cout<<endl<<"arr1 outside the block is:";
            arr1.display( );
            return 0;
}
 

A.)

·        Object arr1 is visible throughout the program but arr2 is visible only within the scope of the inner block.

·        Within the inner block, arr1 is assigned to arr2 (since assignment operator hasn’t been overloaded for the class the compiler provides a default assignment operator which perform bitwise copy operation).

·        Now the pointer of both arr2 and arr1 point to the same memory location.

·        When we exit the inner block, arr2 object will be destroyed (local objects are destroyed at the end of their scope).

·        The destructor of arr2 will free the memory pointed to by ‘ptr’ of object arr2 (which is actually the same memory location as that pointed by ptr of arr1).

·        Now when arr1 tries to retrieve the value stored, it can’t do so because the memory has already been freed. 

Remember: It is advisable to overload the assignment operator and copy constructor in a class which uses dynamic memory allocation. 


Q.) What would be the output of the following? Explain the problem as well. 

class myChar
{
private:
            char alpha;
public:
            myChar(char c):alpha(c)
            {}
            int operator!= (const myChar &right)
            {
                        if (right.alpha!=alpha)
                                    return 1;
                        else
                                    return 0;
            }
};
 

int main( )
{
            myChar ch1('a');
            int i = 97;
            cout<<(ch1 != i);
            return 0;
}
 

A.) The output will be 0. When the compiler encounters:

            ch1! = i

it is equivalent to:

            ch1.operator!=(i);

But the operator!= function requires a character and the compiler will perform an implicit conversion of 97 into a character (97 happens to be the ASCII value for ‘a’). Thus since a= = a, the output will be 0. To avoid this from occurring, we should use an explicit constructor.


Go back to the Contents Page 2


Copyright © 2005 Sethu Subramanian All rights reserved. Sign my guestbook.