Showing posts with label Virtual. Show all posts
Showing posts with label Virtual. Show all posts

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.

Friday, 27 March 2009

Example of Virtual Functions

The following is a simple example of Virtual functions. There is a Shape class which is the base class and three other classes are derived from the Shape class. The Circumference method in the base class is 'pure virtual' so it has to be defined in the derived classes else the compiler will complain about the class being abstract. Note that even if a base class has a single pure virtual function, it would become as an Abstract Base class.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This shows an example of C++ virtual function/methods
//This example also covers a pure virtual method
//This also shows an example of Inheritance
#include<iostream>

using namespace
std;

//Base Class
class Shape {
public
:
virtual
void Area(int length, int breadth)
{

cout<<"Shape: Area = "<<length * breadth<<endl;
}

virtual
void Circumference(int length, int breadth) = 0; //pure virtual
};

//Derived class - Inherits Shape as Public
class Rectangle : public Shape {
public
:
void
Circumference(int length, int breadth)
{

cout<<"Rectangle: Circumference = "<<2*(length + breadth)<<endl;
}
};


//Derived class - Inherits Shape as Public
class Square : public Shape {
public
:
//Overloaded Area because for Square length = breadth
void Area(int length)
{

Shape::Area(length, length);
}

//Overloaded Circumference because for Square length = breadth
void Circumference(int length)
{

cout<<"Square: Circumference = "<<(4 * length)<<endl;
}

void
Circumference(int length, int breadth)
{

Circumference(length);
}
};


//Derived class - Inherits Shape as Private as Area and Circumference
//for Square is very different from the Base class
class Circle : private Shape {
public
:
//Overloaded Area
void Area(int radius)
{

cout<<"Circle: Area = "<<(3.14 * radius * radius)<<endl;
}

//Overloaded Circumference
void Circumference(int radius)
{

cout<<"Circle: Circumference = "<<(2 * 3.14 * radius)<<endl;
}

private
:
//Nobody should call these methods
void Area(int length, int breadth) {};
void
Circumference(int length, int breadth) {};
};


int
main()
{

Rectangle r;
cout<<"\n\nRectangle Class - Dimensions 3 x 4"<<endl;
r.Area(3, 4);
r.Circumference(3, 4);

Square s;
cout<<"\n\nSquare Class - Dimensions 3 x 3"<<endl;
s.Area(3);
Shape *s1 = &s; //possible to access derived class through base
s1->Area(3,3);
s.Circumference(3);

Circle c;
cout<<"\n\nCircle Class - Radius is 3"<<endl;
//c.Area(3,3); //- Not Possible as its private in Circle
c.Area(3);
//Shape *c1 = &c; // not possible because conversion from 'Circle *'
// to 'Shape *' exists, but is inaccessible
//c.Circumference(3,3); //- Not Possible as its private in Circle
c.Circumference(3);
return
0;
}




The output of the program is as follows: