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

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds