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

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

1. Introduction.

1.1 Consider the following C++ base and derived classes :

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

	int x;

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

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

	int y;

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

1.2 Now consider the following example usage of these classes :

void DoTest(Base *pBase)
{
	Derived* pDerived = static_cast<Derived*>(pBase);

	pDerived -> func();

	cout << pDerived -> x << endl;
	cout << pDerived -> y << endl;
}

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

	DoTest(&base);

	return 0;
}

1.3 The above DoTest() function, when executed via _tmain(), will display the following seemingly correct output :

Derived func()
0
200

In DoTest(), after statically casting a pointer to a Base object into a pointer to a Derived object, the following call :

pDerived -> func();

apparently did invoke the derived class’ func() function. And this Derived object seemed to hold both “x” and “y” members.

1.4 However, when the program terminates, the following error message box will be displayed :

StackCorruptedMsgBox

Note that the above message box is displayed when the program is run in the Visual Studio debugger. At runtime, essentially the same error message will be displayed through a different message box.

1.5 So what happened ? How did the Base class object get transformed into a Derived class object ? Is the error message related to the static cast ?

1.6 This 2 part article will closely examine the DoTest() code and analyze whether it really worked correctly. Along the way, we will also study static and dynamic casting and see where these concepts fit into the way things should work.

2. Static Casting.

2.1 So how did the code in DoTest() work ? The answer is : it did not. With _tmain() as the client code, the parameter to DoTest(), pBase, is a pointer to a Base object, not a pointer to a Derived object.

2.2 In the DoTest() function, after statically casting pBase to pDerived, the compiler will blindly treat pDerived as a Derived class object. The compiler will then take it that the memory area starting from the address of pDerived is indeed large enough to hold a Derived class instance.

2.3 The compiler thus assumes that the memory area occupied by pDerived is large enough to hold a “y” member integer.

2.4 This is dangerous because in _tmain(), when the Base class instance base was instantiated, a memory area only large enough for a Base object was allocated.

2.5 Then when the following was executed :

pDerived -> func();

Derived::func() will be executed and the memory location that is assumed to be the “y” member integer will indeed be modified.

2.6 The situation can be seen clearly by looking at the memory area of the Base class object “base” at runtime. Let’s step through the process slowly :

2.6.1 In function _tmain(), after the Base class object base gets constructed, its memory begins at memory location 0x0012FF60 which is as follows :

MemoryView_BaseClassConstructed

The member “x” has been initialized to value 0 and this can be seen in the zero byte values as displayed in red in the Memory Viewer.

2.6.2 Thereafter, DoTest() will be called, followed by a call to Derived::func(). Now at function Derived::func(), the “y” member will be set to value 200.

Look at the memory area of base at this time before member “y” gets modified :

MemoryView_BeforeYGetsModified

Now if base is indeed a Derived class instance, then its “y” member will be located right below its “x” member, at memory location 0x0012FF64. This memory location where “y” is supposed to be is highlighted in the red box in the diagram above. The value is 0xcccccccc.

What is clear from this number is that “base” is not a Derived class object. This is because the Derived class constructor will initialize its “y” member to 0. Since “y” here is non-zero, we know that the highlighted memory area is not part of a Derived class object.

2.6.3 Now right after “y” gets set to value 200 (or 0xC8 in hex), this memory location will change :

MemoryView_AfterYGetsModified

As can be seen in the diagram above, the memory location of “y” gets changed to value 200.

2.6.4 The action of altering the 4-byte memory area at location 0x0012FF64 is basically invalid memory access which results in the error message box as indicated in point 1.4.

2.6.5 And since we are dealing with an object which has been created on the stack (in _tmain(), “base” is a local variable instantiated on the stack area of the _tmain() function), hence the error message box indicates memory corruption in the stack memory area around the variable “base”.

3. In Conclusion.

3.1 Here in part 1, we have examined carefully the implications of invalid static casting.

3.2 Static casting should be done when performing an “upcast” from a derived class to a base class since it is a certainty that a derived class instance would contain a base class sub-object.

3.3 The converse is not always true of course especially when a base class an be instantiated on its own.

3.4 In part 2, we shall continue the discussion with a study of dynamic casting.

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 2 « limbioliong - December 19, 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: