//
you're reading...
C++, Programming Issues/Tips

C++ Static and Dynamic Casting – Example Use Case – Part 2

1. Introduction.

1.1 In part 1 of this series of articles, I have demonstrated the shortcomings of static casting.

1.2 I reasoned that static casting is more appropriate for up-casting from a derived class to a base class and not the other way around.

1.3 So how does one safely perform a down-cast from a base class to a derived one ?

1.4 Enter dynamic casting. The sections that follow will explore this useful C++ language feature.

2. Dynamic Casting.

2.1 C++ dynamic casting is a useful language feature above C-style casting.

2.2 It is accomplished via the use of the dynamic_cast keyword.

2.3 Dynamic casting comes at a cost. To use dynamic casting, 2 things must apply :

  • The involved C++ classes must be polymorphic.
  • Run-time Type Information must be available.

3. Polymorphic C++ Classes.

3.1 In our sample use case, in order to render the Base class polymorphic, at least one of its functions must be declared as virtual. Once this is done, the class is effectively polymorphic. Not only that, all derived classes are polymorphic as well.

3.2 Now, which function of the Base class should we choose to be declared as virtual ? The best function to declare as virtual is the destructor. I shall expound on this in a later section.

4. Run-time Type Information

4.1 In order that the relationship between a derived class and its base class be available during runtime, runtime type information (RTTI) must be available.

4.2 RTTI is produced by the compiler and inserted into the final executable. In order to enable the inclusion of RTTI, the “Enable Run-Time Type Info” setting in the property pages of the project must be set to “Yes” as shown below :

RTTI_property_pages_setting

5. Code Changes.

5.1 Armed with new knowledge above, we need to make code changes in order to ensure success in down-casting a pointer to a base class object to a derived one.

5.2 The Base and Derived classes are now changed to the following :

class Base 
{
public:
	Base() :
		x(0)
	{
	}

	virtual ~Base()
	{
		x = 0;
	}

	int x;

	void func()
	{
		x = 100;
		cout << "Base func()" << endl;
	}
};

class Derived : public Base
{		
public:
	Derived() :
		y(0)
	{
	}

	virtual ~Derived()
	{
		y = 0;
	}

	int y;

	void func()
	{
		y = 200;
		cout << "Derived func()" << endl;	
	}
};

Notice that the Base and Derived class’ destructors have been decorated with the virtual keyword.

5.3 The client code must also be modified :

void DoTest(Base *pBase)
{
	cout << pBase -> x << endl;

	Derived* pDerived = dynamic_cast<Derived*>(pBase);

	if (pDerived)
	{
		pDerived -> func();
		cout << pDerived -> y << endl;		
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	Derived derived;

	DoTest(&derived);

	return 0;
}

The following are the pertinent points about the code above :

  • In function DoTest(), a pointer to a Derived class (pDerived) is obtained through dynamic_cast<>.
  • Before actually using pDerived, it is tested to check if it is NULL.
  • This is the main advantage of using dynamic_cast. If the dynamic_cast fails, then the return value is NULL.

5.4 If _tmain() was coded as follows :

int _tmain(int argc, _TCHAR* argv[])
{
	Base base;

	DoTest(&base);

	return 0;
}

Then in the DoTest() function, the dynamic_cast will fail. pDerived will be NULL and the call to Derived::func() and the access to Derived::y are avoided.

6. The Usefulness of a Virtual Destructor.

6.1 We will now expound on the usefulness of a virtual destructor. When the destructor of a base class has been declared as virtual, then when a derived class object is destroyed via a pointer to its base class, the derived class’ destructor will be executed first followed by that of the base class.

6.2 Let’s say we have the following 2 base and derived classes :

class Base 
{
public:
	Base()
	{
	}

	virtual ~Base()
	{
	}
};

class Derived : public Base
{		
public:
	Derived()
	{
	}

	virtual ~Derived()
	{
	}
};

6.3 Let’s say we have the following code :

Base* pDerived = new Derived();

delete pDerived;

Notice that pDerived is a pointer to a Base class but is instantiated as a Derived class object.

6.4 At runtime, when pDerived is deleted, the code for virtual ~Derived() will be called first followed by virtual ~Base().

6.5 If the Base class destructor is non-virtual, then when pDerived is deleted, the Base class destructor will be called and the Derived class destructor will not be invoked.

7. In Conclusion.

7.1 This concludes our short discussion of C++ static and dynamic casting.

7.2 I hope the reader has gained a better understanding of the purpose of each type of casting.

7.3 Before we end, I would like to draw attention to something mentioned by Herb Sutter and Andrei Alexandrescu in their book “C++ Coding Standards”  concerning downcasting :

If you frequently use dynamic_cast (or, worse, an unchecked static_cast) to perform downcasting, it can be a sign that your base classes offer too little functionality. Consider redesigning your interfaces so that your program can express computation in terms of the base class.

7.4 I think this is sound advise.

Advertisements

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.

Discussion

Trackbacks/Pingbacks

  1. Pingback: C++ Static and Dynamic Casting – Example Use Case – Part 1 « limbioliong - December 20, 2012

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: