Showing posts with label Derived Class. Show all posts
Showing posts with label Derived Class. Show all posts

Wednesday, 2 February 2011

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.

Wednesday, 28 April 2010

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:

Thursday, 30 July 2009

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:


Monday, 29 June 2009

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.

Monday, 22 June 2009

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:

Tuesday, 5 May 2009

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: