Saturday, February 19, 2011

down casting unknown types

In C++ you have classes. Classes are objects that can be based off of other classes. Casting between class types is usually done by.

Foo* f = new Foo()
Bar *b = (Bar*)f;

The problem with this is its not safe. If Bar is not a base class of Foo then b is invalid and will do who knows what. There is a second possible problem too. If Foo has multiple base classes, say Bar and Baz, the cast might not work either. This depends on how the class was declared

class Foo : public Bar, public Baz

or

class Foo : public Baz, public Bar

If it was the first one, the code would have been okay. If it was the second then we just tried to cast a pointer to Baz into a pointer to Bar, which isn't okay. Casting to a base type is called down casting. How do you safely cast into Bar?

Welcome our good friend dynamic_cast. dynamic_cast knows how the classes were declared and will correct cast for you. It'll shift pointers around and return the right thing. And in case you tried to cast to something that is impossible, it returns a null. The one thing dynamic_cast wont do is cast from a void*. This is known as up casting, or casting from a base class to a derived class.

void* v = new Foo();
Bar* b = (Bar*)new Foo();
Foo* x = dynamic_cast(v); // returns null
Foo* y = dynamic_cast(b); // returns Foo*

There is no path to Bar from void, so dynamic_cast wont work here. Using void* as a generic pointer is pretty common, but unfortunately you can't dynamic_cast from it. What you need to do is create a common base class for everything to share. Lets call it Object

class Object{};

class Bar : public Object
{ };
class Baz : public Object
{ };
class Foo : public Bar, public Baz
{};

Now everything shares a common base class called Object. The problem is Foo has 2 Object base classes, one for Bar and one for Baz. If you drew out the memory, it might look something like this.

Foo
+-----
|Object
|Bar
+-----
+-----
| Object
| Baz
+-----

Now, if you tried to cast Foo to Object, which Object should it point to, the one in Bar or the one in Baz. Using a normal (Object*)new Foo() would get you the Object from bar. Using dynamic_cast would result in a compile warning of C4540 (dynamic_cast used to convert to inaccessible or ambiguous base) and it would return null. You can fix this by using a virtual base class.


class Object{};

class Bar : virtual public Object
{ };
class Baz : virtual public Object
{ };
class Foo : public Bar, public Baz
{};

Notice the "virtual public Object". This tells the compiler to only make one Object for Foo, and have Bar and Baz share it. Now dynamic_cast will be able to cast from Object to Foo and vise-versa. Now you can use Object* instead of void* as your generic pointer. This will allow you to dynamic_cast up and down all you want. The one thing you can't use this for is for primitives like int, char, float. But you can't derive anything from that anyway so it shouldn't matter.

One idea, you can use these for a Service Registry. Just make all your services have a virtual base class of IService.

class ServiceRegistry
{
public:
void Add(char* name, IService *i);
IService Find(char* name);
}

// cast to IService to add
reg->Add("my_service", dynamic_cast(my_service) );
// cast from IService to get
MyService* find = dynamic_cast( reg->Find("my_service") );


Thursday, February 3, 2011

Zombies from Microsoft

Apparently there is a bug in windows that causes Zombie Console windows.


Whats a zombie window? Its a window with no process. Every window should have a process associated with it. When that process closes, so should its window. But if the process closes some how without ever closing the window, it turns into a Zombie window.

Zombie windows are bad because they can't be closed and they prevent you from shutting down, and logging out of windows. Windows gets stuck trying to close them.

I have never seen a solution on how to get rid of them, so I came up with my own. I call it Zombie Killer.

What it does is list all your windows and lets you select one to close. You just need to double click the window in the list and it will be handled.