Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


Tip of the Day
Home » Tip Bank » C++
Language: C++
Expertise: Advanced
Dec 9, 2002

Using Prototypes Rather than RTTI


In some situations, you may want a certain data member of two different objects to be identical. For example, suppose you are writing a graphics program that will render a 3D scene, you need to store material properties (such as reflection coefficients) for different objects in the scene. The simplest way to do this to define an abstract base class called Material that is derived from to define different concrete classes of materials.
 
class Material
{
..   // one or more pure virtual functions
};

class MaterialType1 : public Material
{
..  // a concrete class
};

class MaterialType2 : public Material
{
..  // a concrete class
};

Now objects may contain a pointer to a material object:
 
class Object
{
private:
Material *mtrl;
..

public:
void SetMaterial(Material *m) { mtrl = m;}
Material *GetMaterial() const { return mtrl; }
..
};

Suppose you want two objects to have exactly the same material properties, but you don't want to share the material object between them. The first object's material is set as follows:
 
Object obj1, obj2;
obj1.SetMaterial(new MaterialType1);
.. // set various material properties

To set the material of obj2 to the same material as of obj1, you can't use this code:
 
obj2.SetMaterial(new Material(obj1.GetMaterial()));

This is because Material is an abstract class and cannot be instantiated with 'new'. You need to know the dynamic type of obj1's material. Using run-time type information (RTTI) is an inelegant and inflexible solution:
 
if (typeid(obj1.GetMaterial()) == typeid(MaterialType1))
  obj2.SetMaterial(new MaterialType1(obj1.GetMaterial());
else if (typeid(obj1.GetMaterial() == typeid(MaterialType2))
  obj2.SetMaterial(new MaterialType2(obj1.GetMaterial());

Not only does the caller need to know the dynamic type of the material, but if you now add other classes to the Material class hierarchy, the if-statement will need to be changed to accommodate the new types as well. This is clearly not desirable.

A better way is to use the Prototype design pattern. First, define a Clone function for each class in the Material hierarchy:
 
class Material
{
public:
virtual Material *Clone() const = 0;
..
};

class MaterialType1 : public Material
{
public:
virtual MaterialType1 *Clone() const
{ return new MaterialType1(*this); }
..
};

class MaterialType2 : public Material
{
public:
virtual MaterialType2 *Clone() const
{ return new MaterialType2(*this); }
..
};

To add a new class to this hierarchy, just make sure that it defines the Clone function. To set obj2's material properties to the same as obj1's, simply say:
 
obj2.SetMaterial(obj1.GetMaterial()->Clone());

The existing material object in obj1 functions as a prototype, replicating itself and returning the result. The caller need never know the dynamic type of the material, and you don't need to change this code if the Material class hierarchy changes.
Abhijeet Vijayakar
 
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date