Showing posts with label derived class. Show all posts
Showing posts with label derived class. Show all posts

Consequences of Ignoring Compiler Warnings

Though this is a fictional program that I have picked up from here, I have seen similar problems in real life.

Lets say my program (below) was expected to return this


but instead returned:

Program as follows:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>

using namespace
std;

class
Bclass
{

public
:
Bclass() {}
virtual
void func()
{

cout<<"In Bclass::func()"<<endl;
}
};


class
Dclass : public Bclass
{

public
:
Dclass() {}
virtual
void func()
{

cout<<"In Dclass::func()"<<endl;
Bclass:func();
}
};


int
main()
{

Dclass d;
d.func();
//...
return 0;
}



The clue of the problem was given by the compiler that generated the following warning:

main.cpp(23) : warning C4102: 'Bclass' : unreferenced label

pointing to the line

Bclass:func();

The problem lies in the fact that due to a single : rather than :: the line above is being treated as label and since its an unreferenced label it goes back to the start of the same function.

You can read the complete discussion here. Make sure to check the warnings the next time your program behaves unexpectedly.

Interview Question on the Slicing Problem

Someone was talking about the Slicing Problem with classes in one of the companies we do projects for. As the name states, the Slicing problem arises when a part of the class is Sliced away. This will happen when derived class is assigned to the base class. Here is a simple example that is also been used for interviews:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>

using namespace
std;

class
Parent
{

public
:
virtual
void func_a(void);
};


class
Child : public Parent
{

public
:
void
func_a(void);
};


void
func_1(Parent p);
void
func_2(Parent* p);
void
func_3(Parent& p);


int
main()
{

//Using the Parent class
Parent p;
cout<<"\nParent Class"<<endl;
func_1(p);
func_2(&p);
func_3(p);

//Using the Child class
Child c;
cout<<"\n\nChild Class"<<endl;
func_1(c);
func_2(&c);
func_3(c);

//Using the Parent class that is initialised to class
Parent p2 = c; //Note that in p2, additional info about c would be lost
cout<<"\n\nParent p2 Class"<<endl;
func_1(p2);
func_2(&p2);
func_3(p2);

//Not possible to initialise directly from base to derived class.
//Child c2 = p2; - ERROR: cannot convert from 'Parent' to 'Child'
//The way round it would be to have a constructor or overload operator =

return
0;
}


void
Parent::func_a()
{

cout<<"Parent::func_a()"<<endl;
}


void
Child::func_a(void)
{

cout<<"Child::func_a()"<<endl;
}


void
func_1(Parent p)
{

cout<<"func_1 -> ";
p.func_a();
}


void
func_2(Parent* p)
{

cout<<"func_2 -> ";
p->func_a();
}


void
func_3(Parent& p)
{

cout<<"func_3 -> ";
p.func_a();
}





The output is as follows:

Virtual Base class Inheritance


Came across this interesting case of multiple base class inheritance which can result in compilation errors.

Figure above demonstrates the ambiguity that can occur in diamond inheritance. The program defines class Base, which contains pure virtual function print. Classes DerivedOne and DerivedTwo each publicly inherit from class Base and override the print function. Class DerivedOne and class DerivedTwo each contain what the C++ standard refers to as a base-class subobject—i.e., the members of class Base in this example.

Class Multiple inherits from both classes DerivedOne and DerivedTwo. In class Multiple, function print is overridden to call DerivedTwo’s print.

Function main declares objects of classes Multiple, DerivedOne and DerivedTwo. main also declares an array of Base * pointers. Each array element is initialized with the address of an object. An error occurs when the address of both—an object of class Multiple—is assigned to array[ 0 ]. The object both actually contains two subobjects of type Base, so the compiler does not know which subobject the pointer array[ 0 ] should point to, and it generates a compilation error indicating an ambiguous conversion.

The problem of duplicate subobjects is resolved with virtual inheritance. When a base class is inherited as virtual, only one subobject will appear in the derived class—a process called virtual base-class inheritance.



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example showing virtual base class inheritance
//http://www.deitel.com/articles/cplusplus_tutorials/20060225/virtualBaseClass/index.html

#include <iostream>
using std::cout;
using
std::endl;

// class Base definition
class Base
{

public
:
virtual
void print() const = 0; // pure virtual
}; // end class Base

// class DerivedOne definition
//class DerivedOne : public Base - REF1
class DerivedOne : virtual public Base
{

public
:
// override print function
void print() const
{

cout << "DerivedOne\n";
}
// end function print
}; // end class DerivedOne

// class DerivedTwo definition
//class DerivedTwo : public Base - REF2
class DerivedTwo : virtual public Base
{

public
:
// override print function
void print() const
{

cout << "DerivedTwo\n";
}
// end function print
}; // end class DerivedTwo

// class Multiple definition
class Multiple : public DerivedOne, DerivedTwo
{

public
:
// qualify which version of function print
void print() const
{

DerivedTwo::print();
}
// end function print
}; // end class Multiple

int
main()
{

Multiple both; // instantiate Multiple object
DerivedOne one; // instantiate DerivedOne object
DerivedTwo two; // instantiate DerivedTwo object
Base *array[ 3 ]; // create array of base-class pointers

array[ 0 ] = &both; // ERROR - ambiguous if REF1 and REF2 used
array[ 1 ] = &one;
array[ 2 ] = &two;

// polymorphically invoke print
for ( int i = 0; i < 3; i++ )
array[ i ] -> print();

return
0;
}
// end main

The output is as follows:


The case for 'virtual destructor'

You may often find that the destructor of your class is virtual. The main reason for having virtual destructor stems from the fact that some other class may derive from your class. If the derived object is referenced as base object and destroyed then the derived class objects wont be deleted. To overcome this problem we define the destructor virtual . Lets look at an example:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example showing the need for Virtual Destructor
#include <iostream>

using namespace
std;

class
Base
{

public
:
Base() {
cout<<"Base Constructor Called"<<endl;
}
~
Base() {
cout<<"Base Destructor Called"<<endl;
}
};


class
Derived : public Base
{

public
:
Derived() {
cout<<"Derived Constructor Called"<<endl;
}
~
Derived() {
cout<<"Derived Destructor Called"<<endl;
}
};


int
main()
{

cout<<"\nTESTING NON-VIRTUAL BASE DESTRUCTOR\n";
Base *b = new (Derived);
delete
(b);
return
0;
}


The output is as follows:

Now lets modify the base destructor to make it virtual.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example showing the need for Virtual Destructor
#include <iostream>

using namespace
std;

class
Base
{

public
:
Base() {
cout<<"Base Constructor Called"<<endl;
}

virtual
~Base() {
cout<<"Base Destructor Called"<<endl;
}
};


class
Derived : public Base
{

public
:
Derived() {
cout<<"Derived Constructor Called"<<endl;
}
~
Derived() {
cout<<"Derived Destructor Called"<<endl;
}
};


int
main()
{

cout<<"\nTESTING VIRTUAL BASE DESTRUCTOR\n";
Base *b = new (Derived);
delete
(b);
return
0;
}



The modified output is as follows:


There is one more point to be noted regarding virtual destructor. We can't declare pure virtual destructor. Even if a virtual destructor is declared as pure, it will have to implement an empty body (at least) for the destructor.

You can read more about this at C++ FAQ.

An example of dynamic_cast

Lets look at an example of dynamic_cast where you can cast a pointer from Derived class to Base class. The example should be self explanatory:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//A very simple program to explain dynamic cast

#include <iostream>

using namespace
std;

//Base class
class A
{

public
:
int
a;
int
b;
private
:
int
c;
};


//Derived class
class B :public A
{

private
:
int
d;
};


//function that prints a and b
void function(A a)
{

cout<<"\n a = "<<a.a<<" b = "<<a.b<<endl;
}


int
main()
{

A *a;
B *b=new(B);
b->a = 20, b->b = 40;
a = dynamic_cast<A*>(b); //Dynamic cast from Dervied to Base
function(*a);
return
0;
}



The output is as follows:

An example of Interface class

Sometimes it is simple and helpful to define a class that does nothing but defines a standardised interface that can be used by other classes to make sure the implementation follows a standard set of input and output paramaters. Also this approach results in faster code runs and more maintainable code.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This program shows an example of Interface class

#include<iostream>

using namespace
std;

//Shape is an Interface Class. No data and everything pure virtual
class Shape {
public
:
virtual
void Area(int length, int breadth) = 0;
virtual
void Perimeter(int length, int breadth) = 0;
//Note, no data
};

//Derived class - Inherits Shape as Public
class Rectangle : public Shape {
public
:
void
Area(int length, int breadth);
void
Perimeter(int length, int breadth);
private
:
int
someData;
};


//Derived class - Inherits Shape as Public
class Triangle : public Shape {
public
:
void
Area(int length, int breadth);
void
Perimeter(int length, int breadth);
private
:
int
someData;
};


int
main()
{

Rectangle r;
Triangle t;

cout<<"\n\n";
r.Area(3,4);
r.Perimeter(3,4);

t.Area(3,4);
t.Perimeter(3,4);

cout<<"\n\n";
return
0;
}


void
Rectangle::Area(int length, int breadth)
{

cout<<"\nThe Area of Rectangle for length = "<<length<<" and\
breadth = "
<<breadth<<" is "<<(length * breadth)<<endl;
}


void
Rectangle::Perimeter(int length, int breadth)
{

cout<<"\nThe Perimeter of Rectangle for length = "<<length<<" and\
breadth = "
<<breadth<<" is "<<2 * (length + breadth)<<endl;
}


void
Triangle::Area(int length, int breadth)
{

cout<<"\nThe Area of Triangle for length = "<<length<<" and\
breadth = "
<<breadth<<" is "<<(length * breadth)/2<<endl;
}


void
Triangle::Perimeter(int length, int breadth)
{

cout<<"\nThe Perimeter of Triangle for length = "<<length<<" and\
breadth = "
<<breadth<<" is "<<(length * breadth)/3<<endl;
}


In the above example, Shape class is an 'abstract class'. All the interfaces are 'pure interfaces'. It contains no data. The derived classes now have to define the interace functions.

The output is as follows:

Initialization lists and base class members

Just some thoughts upon a question that I ran across, raised about, why you could not initialize base class members in derived classes. Put it another way, why could you not use the base class data members in derived class' initialization lists. Simplest reason - the standards, the language rules don't allow it. But let's have some fun with the "what-if"s.

One reason that struck me almost as a first thought, that the data member could be private in which case, you won't have access to it in the derived class. But what if it is public or protected? Let us take an example:


    class Base
    {
    public:
        Base(){}
        Base(int member_) : member (member_){}
        int member;
        //other members
    };

    class Derived : public Base
    {
    public:
        Derived(int member_) : member(member_){}
        //other members
    };

    int main()
    {
        Derived derivedObject(10);
    }


You would have expected it to work since the base member is accessible in the derived class, it being public. After all, it is perfectly okay if you used it in the derived class constructor body! What is so special about initialization lists that only direct base classes, virtual bases and the containing class' data members can only appear?

You might think that the base class object might not have been allocated or does not exist at all while in the initialization list of the derived class and hence it is not allowed to do that. But that reasoning would be flawed. Why? For the following reason (quoting section 12.6.2 (5) from the standards):

Initialization shall proceed in the following order:

    — First, and only for the constructor of the most derived class as
described below, virtual base classes shall be initialized in the
order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is
the order of appearance of the base class names in the derived
class base-specifierlist.

    — Then, direct base classes shall be initialized in declaration order
as they appear in the base-specifier-list (regardless of the order
of the mem-initializers).

    — Then, non-static data members shall be initialized in the order
they were declared in the class definition (again regardless of
the order of the mem-initializers).

    — Finally, the body of the constructor is executed.

    [ Note: the declaration order is mandated to ensure that base and
member subobjects are destroyed in the reverse order of initialization.
    —end note ]

So, the base is already initialized before anything else happens in the initialization list. What could be the reason then? The reason probably is that it does not make sense! Once the base constructor has initialized the base member, the derived class initializing it does not make sense. How can one thing be initialized twice? The second time, it has to be an assignment.

But again, that holds true just for non-POD members. For the object being constructed in the above code, via default constructor of the base class, the POD member "member" remains uninitialized! It will have an indeterminate value. So, it won't be double initialization, would it? It would be initialized just once and that from the derived class constructor (initialization list).

Now, consider there were a further derived class that publicly derived from the above "Derived" class having the same member initialization syntax. Now, that makes it two. This could probably have been dealt with some complication set of rules but why add that logical overhead?

That is not all though. The *rules* can get more complex. The consideration of different access specifiers (private/protected), different inheritance types (private/protected), an explicit constuctor call that too initializes the member, virtual bases, different treatment for non-POD and POD types and what not. Things just start to get too complex and dirty if you allow that.

Simply speaking, base class members should be the base class' responsibility and derived class should only be concerned with the construction abstraction provided by the base classes in form of the base constructors and their initialization lists. Making things more coupled is always a sign of bad design choice where things just start to fall apart as soon as something changes. That is not good code.

To make things clear and simpler, it's best said and accepted that the standard does not allow it for initialization lists to take up the responsibility of initializing base class members, just the immediate bases, virtual bases and class' members.

Have fun... Cheers!

Check out this stream