New cast operators with additional features
Posted by Kaya Kupferschmidt • Friday, April 7. 2006 • Category: C++
C++ already has a rich set of casting operatos, ranging from old-style C casts, over static_cast, dynamic_cast and the almost-never-to-be-used reinterpret_cast. Sometimes it might be convenient to have something similar like a dynamic_cast but with another behaviour if the cast fails. For example one might want to get an exception if a specific cast is not possible.
It turns out that this is pretty easy using templates with the following code
But we still can do better than this, because we might want to configure which exception should be thrown on a casting failure. The code above can be easily modified to:
The next idea that might come to mind is to use a default-exception, that is something like follows:
Unfortunately this is not possible, as only class templates may have default values for their template parameters. So we have to find a workaround. A (in my opinion rather neat) solution looks like follows:
Now yow can use this cast-operator in both ways:
It turns out that this is pretty easy using templates with the following code
template<class T,class S> T* throwing_cast(S* s) {
T* result = dynamic_cast<T>(s);
if (!result)
throw bad_cast_exception();
return result;
}
ClassA* a = new ClassB();
ClassB* b = throwing_cast<ClassB>(a);
But we still can do better than this, because we might want to configure which exception should be thrown on a casting failure. The code above can be easily modified to:
template<class T,class E,class S> T* throwing_cast(S* s) {
T* result = dynamic_cast<T>(s);
if (!result)
throw E();
return result;
}
ClassA* a = new ClassB();
ClassB* b = throwing_cast<ClassB,MyException>(a);
The next idea that might come to mind is to use a default-exception, that is something like follows:
template<class T,class E=BadCastException,class S> T* throwing_cast(S* s) {
T* result = dynamic_cast<T>(s);
if (!result)
throw E();
return result;
}
Unfortunately this is not possible, as only class templates may have default values for their template parameters. So we have to find a workaround. A (in my opinion rather neat) solution looks like follows:
template<class T,class E = Exception>
class throwing_cast {
public:
template<class S>
inline throwing_cast(S s) {
T result = dynamic_cast<T>(s);
if (!result)
throw E();
m_Object = result;
};
inline operator T() {
return m_Object;
};
private:
T m_Object;
};
Now yow can use this cast-operator in both ways:
ClassA* a = new ClassB();
ClassB* b =
throwing_cast_old<ClassB*,Exception>((ClassA*)a);
ClassB* c = throwing_cast<ClassB*>((ClassA*)a);



6 Comments
I do not get used to the XXX_cast operators in C++ yet - yes, I cast by old C way. I could start using static_cast, which is OK, but I hate the underline in keyword - should not be there
The problem with e.g. reinterpret_cast is that it can throw .. a bad_cast exception .. which is not in my hierarchy of exceptions (as I do not use STL). And what to do then? Add a catch to all try blocks? Not a good idea. Again, a simple thing gets very complicated in C++.
Concerning the cast-operators, I had used the old-style cast operators for a long time time, but as soon as you use multiple base classes or virtual inheritance, a dynamic_cast operator is a must. Plus you can check in a very elegant way if a pointer to some base class is deriveable to another class at runtime - you will get back a null pointer if the object is not of the desired type.
And reinterpret_cast is something you should almost never use. Mst of the time, a static_cast will just do fine, it is essentially the same as old C-style casts. And for cross-casting in a hierarchy, a dynamic_cast is probably the only safe way.
C++ is definately not simple, but it offers a lot of power. The only thing that is really, really broken are exception specifications. In every good book the author will explicitly discourage one to use them. That's really a pity, because I really liked the idea (which I first saw in Java) of specifying exceptions.
The dynamic_cast and others require some RTTI information to be compiled, do not? I am not sure on this.
You are also right about dynamic_cast, it really needs RTTI information to be compiled in your files. But this is some useful information anyway, although it is still far too limited to be really useful.
Maybe I will have a closer look at C# later this year, I am still thinking about using C# for building some GUI for my 3d engine. Do you happen to know if C# works well with unmanaged C++ code?
Actually, I did not try the C# a lot. Partly due to the lack of time, partly because I do not like the Microsoft's way of development (Visual everything .. I love working with files, no visual at all). Also, I do not want to spend my CPU cycles (and power watts) into interpreting something in the "managed" code (sounds like the programmer cannot manage it, so the machine MUST) .. I am an old-school assembler guy
So what language would you propose?
Add Comment