Wednesday, February 12, 2014

Virtual Functions and Inheritance

Inheritance helps to reduce the amount of code written or repeated by using a base-derived relation in object-oriented-world. Common functions are collected in a base class and the derived class extends or directly uses the existing base class functions. In some situations base class also can be pointing to different derived classes depending on the run-time behavior.

When base class is used to point to derived class, base class pointer calls overridden base-class methods, if there are any base class virtual method re-implementations in the derived class. Virtual functions in C++ help to transfer a specific behavior in the base class to derived class by declaring the function virtual in the base class. Derived is free to re-implement base class virtual functions.

If the derived class does not provide any implementation for the base class virtual functions then the base class virtual functions are called. This is not always the expected behavior because base class virtual functions are declared to be overridden in the derived class.

Following sample project created by qt creator and contains following files:
1- VirtualFunctions.pro
2- main.cpp
3- abstractservice.h
4- abstractservice.cpp
5- activityservice.h
6- activityservice.cpp
7- userservice.h
8- userservice.cpp



VirtualFunctions.pro file contains project configuration.

TARGET = VirtualFunctions
CONFIG   += console
TEMPLATE = app
SOURCES += main.cpp \
    abstractservice.cpp \
    userservice.cpp \
    activityservice.cpp

HEADERS += \
    abstractservice.h \
    userservice.h \
    activityservice.h

abstractservice.h is the base class that contains virtual functions.

#ifndef ABSTRACTSERVICE_H
#define ABSTRACTSERVICE_H

#include <stdio.h>

class AbstractService
{
public:
    AbstractService();
    virtual ~AbstractService();
    // calls both base and derived dest
    // prevents memory leaks

    virtual void insertRecord();
    virtual void selectRecord();
    virtual void deleteRecord();
    virtual void updateRecord();

};

#endif // ABSTRACTSERVICE_H

In the base class abstractservice.h destructor is also defined virtual otherwise derived class destructor is not called at object deletion.

abstractservice.cpp is the base class implementation file that contains implementations for virtual functions, constructor and destructor.

#include "abstractservice.h"

AbstractService::AbstractService()
{
    printf("AbstractService::AbstractService called\n");
}

AbstractService::~AbstractService()
{
    printf("AbstractService::~AbstractService called\n");
}

void AbstractService::insertRecord()
{
    printf("AbstractService::insertRecord called\n");
}

void AbstractService::selectRecord()
{
    printf("AbstractService::selectRecord called\n");
}

void AbstractService::deleteRecord()
{
    printf("AbstractService::deleteRecord called\n");
}

void AbstractService::updateRecord()
{
    printf("AbstractService::updateRecord called\n");
}

userservice.h is the first derived class that contains its own implementations for the virtual functions that are declared in the base class abstractservice.
#ifndef USERSERVICE_H
#define USERSERVICE_H

#include "abstractservice.h"

class UserService : public AbstractService
{
public:
    UserService();
    ~UserService();

    void insertRecord();
    void selectRecord();
    void deleteRecord();
    void updateRecord();
};

#endif // USERSERVICE_H

userservice.cpp contains implementation details for the base class virtual functions.
#include "userservice.h"

UserService::UserService()
{
    printf("UserService::UserService called\n");
}

UserService::~UserService()
{
    printf("UserService::~UserService called\n");
}

void UserService::insertRecord()
{
    printf("UserService::insertRecord called\n");
}

void UserService::selectRecord()
{
    printf("UserService::selectRecord called\n");
}

void UserService::deleteRecord()
{
    printf("UserService::deleteRecord called\n");
}

void UserService::updateRecord()
{
    printf("UserService::updateRecord called\n");
}

activityservice.h is the second derived class that re-declares base class virtual functions in its header.
#ifndef ACTIVITYSERVICE_H
#define ACTIVITYSERVICE_H

#include "abstractservice.h"

class ActivityService : public AbstractService
{
public:
    ActivityService();
    ~ActivityService();

    void insertRecord();
    void selectRecord();
    void deleteRecord();
    void updateRecord();
};

#endif // ACTIVITYSERVICE_H

activityservice.cpp file contains implementation details for the base class virtual functions.
#include "activityservice.h"

ActivityService::ActivityService()
{
    printf("ActivityService::ActivityService called\n");
}

ActivityService::~ActivityService()
{
    printf("ActivityService::~ActivityService called\n");
}

void ActivityService::insertRecord()
{
    printf("ActivityService::insertRecord called\n");
}

void ActivityService::selectRecord()
{
    printf("ActivityService::selectRecord called\n");
}

void ActivityService::deleteRecord()
{
    printf("ActivityService::deleteRecord called\n");
}

void ActivityService::updateRecord()
{
    printf("ActivityService::updateRecord called\n");
}

Both of the derived classes provide their own implementations for the virtual functions declared in the base class abstractservice.

main.cpp file contains a main function that is creating different base class pointers which are pointing to derived class objects.
#include "userservice.h"
#include "activityservice.h"

int main(int argc, char *argv[])
{
   UserService *userServicePtr = new UserService;
   userServicePtr->insertRecord();
   userServicePtr->selectRecord();
   userServicePtr->updateRecord();
   userServicePtr->deleteRecord();
   delete userServicePtr;
   printf("\n");

   AbstractService *abstractServiceObjPtr = new AbstractService;
   abstractServiceObjPtr->insertRecord();
   abstractServiceObjPtr->selectRecord();
   abstractServiceObjPtr->updateRecord();
   abstractServiceObjPtr->deleteRecord();
   delete abstractServiceObjPtr;
   printf("\n");

   // base class pointer to derived class object
   char option = 'a';
   AbstractService *serviceObjPtr;
   if( option == 'u' )
   {
       serviceObjPtr = new UserService;
       serviceObjPtr->insertRecord();
       serviceObjPtr->selectRecord();
       serviceObjPtr->updateRecord();
       serviceObjPtr->deleteRecord();
       delete serviceObjPtr;
       printf("\n");
   }
   else if( option == 'a' )
   {
       serviceObjPtr = new ActivityService;
       serviceObjPtr->insertRecord();
       serviceObjPtr->selectRecord();
       serviceObjPtr->updateRecord();
       serviceObjPtr->deleteRecord();
       delete serviceObjPtr;
       printf("\n");
   }

   return 0;
}

At runtime base class pointer serviceObjPtr points to either UserService instance or ActivityService instance.

Console output also shows the order for object creation and destruction.


No comments:

Post a Comment