Can pure virtual functions be defined as well?

A class that contains pure virtual functions is called abstract or interface class and concrete class derived from abstract class is called implementation class. Since abstract class just defines the interface i.e. what data a class contain and what operations can be performed on it. Virtual functions in abstract class are usually declared but not defined. It is the responsibility of derived class to define it.

Declaration of pure virtual function in C++:

virtual <return type> <user defined function name>(<arguments>) = 0; 
e.g.
virtual void Speak(int a) =  0;

But compiler does not complain even if you give the definition of pure virtual function and in some cases it is useful. Let us try to understand where it can be helpful and when that function get called as there can not be object of abstract class.

Let us say we have base class Aeroplane and AeroplaneA and AeroplaneB are derived from it. class Aeroplane has a method called fly() that defines general way of flying. Let us say AeroplaneA and AeroplaneB  have their own way of flying because they are special sort of planes (Jet or something :P). How can we design it in C++?

First approach:   Make function fly() pure virtual and define the fly() function in every class which is an intuitive solution.

  But let us say for another 3 Aeroplanes C, D and E have same general of flying(They are not special kind of planes). In that case you will have to copy the code of fly() function of Aeroplane class to the fly() function of class AeroplaneC, AeroplaneD and AeroplaneE that is duplicate code and moreover let us say there is some bug in flying functionality you will have to change 3 functions and you may forget to modify one or two of them. Hence It is really difficult to maintain.

class Aeroplane {
// constructor,destrcutor etc
public :
   virtual void fly() = 0;
} ;
class AeroplaneA : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
     //own functionality
  }
} ;
class AeroplaneB : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
       //own functionality
   }
} ;
class AeroplaneC : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
     // general fly functionality Duplicate code
   }
} ;
class AeroplaneD : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
     // general fly functioanlity.. Duplicate code
   }
} ;
//similarly for AeroplaneE

Second Approach :  Make function fly() virtual instead of pure virtual. Put the general flying functionality in fly() function of Aeroplane class and whichever class wants to override this functionality it can do. 

    Now we don't need to declare fly() function in AeroplaneC,AeroplaneD and AeroplaneE. Hence for objects of type AeroplaneA or AeroplaneB their own version of fly() will be called. and for rest of the Aeroplanes general fly() function in Aeroplane class will be called. 

class Aeroplane {
// constructor,destrcutor etc
public :
   virtual void fly() {
      // general fly functionality
   }
} ;
class AeroplaneA : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
     //own functionality
  }
} ;
class AeroplaneB : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
       //own functionality
   }
} ;
class AeroplaneC : public Aeroplane{
// constructor,destrcutor etc
// don't need to define fly function here

} ;
class AeroplaneD : public Aeroplane{
// constructor,destrcutor etc
// don't need to define fly function here
} ;

It looks perfect. Isn't it?

But unfortunately answer is No.  It can also cause some problems. e.g.

 Let us say another AeroplaneF(special plane) which has its own way of flying is introduced and designer forget to over ride the fly() function, compiler will not complain, your code will just start working without even a warning. It will be caught as part of bug etc. But what if it is not even caught in testing? For crucial and such critical design you can not take risk or you should not do such mistakes. During the actual run, your Aeroplane may just crash. :(

So what do we do? Neither solution looks like a good solution. Both are bug prone. 

Don't worry we will not let your plane crash.. :) C++ compiler gives you a very nice solution for such problems. 

Solution : Define pure virtual function.  By defining pure virtual function, we can put general fly() functionality in fly() function of Aeroplane and since fly() function is pure virtual all concrete class needs to redefine it and there we can simply call fly() function of class Aeroplane. Hence we have taken care of both problems.  Now there is no duplicate code and compiler enforces you to define virtual function in each concrete class.

class Aeroplane {
// constructor,destrcutor etc
public :
   virtual void fly() = 0 {
      // general fly functionality
   }
} ;
class AeroplaneA : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
     //own functionality
  }
} ;
class AeroplaneB : public Aeroplane{
// constructor,destrcutor etc
public :
   virtual void fly() {
       //own functionality
   }
} ;
class AeroplaneC : public Aeroplane{
// constructor,destrcutor etc
  virtual void fly() {
       Aeroplane::fly();
  }

} ;
class AeroplaneD : public Aeroplane{
// constructor,destrcutor etc
virtual void fly() {
       Aeroplane::fly();
  }


 
} ;

Reference : One of the Item from 50 specific ways to improve your C++ skills by Scott Meyer.

No comments:

Post a Comment

Thanks for your valuable inputs/feedbacks. :-)