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: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds