Polymorphism and Template-Based Designs

Abstraction

Currently, the most-used method of implementing polymorphism in C++ is by using inheritance and virtual functions. The same thing also can be designed using templates.

Some of the design decisions based on virtual functions and inheritance (dynamic polymorphism) are:

  1. Increases the complexity
  2. Becomes fat and time consuming
  3. Less flexible

By carefully designing the applications using the templates, you can solve these design problems.

Polymorphic-Based Design Through Inheritance and Virtual Functions (Dynamic Polymorphism)

  1. Identify the abstraction.
  2. Declare the common methods in the abstract base class as virtual.
  3. Provide the context-dependent implementations in the derived classes.

For example:

class File {
   public:
      virtual void Open() = 0;
      virtual void Save() = 0;
      virtual void SaveAS(String&) = 0;
      virtual void Close() = 0;
};
class TextFile:public File{
   public:
      void Open();
      void Save();
      void SaveAS(String&);
      void Close();
};
class ImageFile:public File{
   public:
      void Open();
      void Save();
      void SaveAS(String&);
      void Close();
};

// user menu selection to open the file
void menu_open_file(File* f_ptr){
   f_ptr->Open();
   ....
   ...
}

By using the above code, you would have the following:

File *file_ptr = new TextFile();
menu_open_file(file_ptr);//open the text file
.
.
file_ptr = new ImageFile();
menu_open_file(file_ptr);//open the image file
  1. In above example, the file is the abstraction. It has been declared as an abstract base class.
  2. Open, Save, SaveAs, and Close are common methods that are declared as virtual in the File class.
  3. Concrete implementations of the file abstractions are the image file and text file that are provided the context-dependent implementations.
  4. This will work along with the Open, Close, Save, and SaveAS menu operations.
  5. If user selects File Open, based on the file type, the menu selection function calls the context-dependent function.

Template-Based Polymorphic Design

Templates will not force you to declare the common methods in the base class. But, they will force the application to declare the common methods implicitly.

Designing the above example using the template based design:

class TextFile{
 public:
   void Open();
};

class ImageFile{
 public: 
  void Open();
};

//user menu selection to open the file

template<typename T> void menu_open_file(T file){
   file.Open();
}

Using the code:

TextFile txt_file;
ImageFile img_file;
menu_open_file(txt_file);    //open the text file
menu_open_file(img_file);    //open the image file
  1. Define the concrete classes text file and image file.
  2. Define the client code as template: menu_open_file.
  3. In templates, there is no need to use pointers or references.

Polymorphism and Template-Based Designs

Some Design Issues with Dynamic Polymorphism-Based Designs (Inheritance and Virtual Function)

The Cost in Time and Memory Usage

Implementation of container classes using dynamic polymorphism is the price of this approach; it is high both in terms of running time and memory usage. This can be avoid by using template-based design. The best example is the Standard template library.

The following container application design is based on inheritance. This is the most popular method of designing before the templates are added to the C++.

class container{
 public:
   add()
   delete()
   print();
};
class list: container{
   .
   .
   .

};
class vector: container{
   .
   .
   .
};

void Sort(container& con){
   .
   .
   .
}

bool Search(Contaner& con)
{
   .
   .
   .
}

Polymorphism Using Inheritance Is Less Flexible

Adding/modifying/removing the common methods (base class interfaces) is costly and error prone. Sometimes, this triggers a chain reaction. If you need more flexibility from the interface point view, it's better to go for template-based designs.

class File{
public:
   virtual void Save()= 0;
   virtual void SaveAs(string& file_name)=0;
   virtual void Open()=0;
};

class TextFile:public File{
 public:
   void Save();
   void SaveAs(string& file_name);
   void Open();
};

class ImageFile:public File{
 public:
   void Save();
   void SaveAs(string& file_name);
   void Open();
};

class BinaryFile:public File{
  public:
   void Save();
   void SaveAs(string& file_name);
   void Open();
};

Suppose you want add print functionality to file abstraction. The problem here is that adding the print functionality to a binary file is not possible because you should not offer to print a binary file.

One possible solution might be to use RTTI; this is not a better option. This will trigger lots of changes in the existing code. Otherwise, you have to split the classes into two hierarchies based on printable and non-printable characteristics.

Alternative Design Using the Templates

class TextFile{
  public:
   void Save();
   void SaveAs(string& amp; file_name);
   void Open();
   void Print();

};

class ImageFile{
  public:
   void Save();
   void SaveAs(string& file_name);
   void Open();
   void Print();
};

class BinaryFile{
  public:
   void Save();
   void SaveAs(string& file_name);
   void Open();

};

template <typename T>
void On_Open( T file){
   file.Open();
}
template <typename T>
void On_Save( T file){
   file.Save();
}
template <typename T>
void On_Print( T file){
   file.Print();
}


TextFile txt_file;
ImageFile img_file;
BinaryFile bin_file;

On_Print(txt_file);
On_Print(img_file);
On_Print(bin_file);   //it will be a error

If try to print a binary file it will be a compile time error.

Conclusions

  1. Both approaches have their own problems and benefits.
  2. Template-based design is a better alternative for dynamic polymorphism-based designs.
  3. You have to choose your approach based on your design goals such as level of re-usability, flexibility, and performance required.

Static polymorphism (template-based) design has the following advantages over dynamic polymorphism (virtual functions-based):

  • Type safe
  • Faster execution of the code
  • No need to express the common interfaces in the bases classes
  • Less coupled, so re-usability will increase.

Dynamic polymorphism (template-based) has the following advantages over static polymorphism (virtual functions-based):

  • Executable code size is smaller
  • No need to publish the source code


About the Author

Akshay Saidulu

Currently working in Infineon tech.India. Very much passionate about software architecture and c++ && OO based designs .

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • When it comes to desktops – physical or virtual – it's all about the applications. Cloud-hosted virtual desktops are growing fast because you get local data center-class security and 24x7 access with the complete personalization and flexibility of your own desktop. Organizations make five common mistakes when it comes to planning and implementing their application management strategy. This eBook tells you what they are and how to avoid them, and offers real-life case studies on customers who didn't let …

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds