Every once in a while, you can teach an old dog new tricks. This old dog has learned a few in recent months, so I wanted to throw them out there for giggles.
Templates, Method Overloading and Superclasses, oh my!
I recently ran into a case where I wanted to make a specialized subclass of a C++ template class so that I could override some of its functionality for testing purposes. The really odd part about it was the fact that I eventually wanted to call through to the base class' functionality to perform the original work -- I just need to add some specific logging code (without any sort of access to IsA in C++). It turns out, this is hard. :-PGiven the following C++ template class:
template< T >
class SimpleVector {
public:
// Some stuff
inline T& operator[]( const unsigned long index );
// Some other stuff
};
I wanted to subclass SImpleVector, but for a specific type, so that I could add some logging code to the array accessor. I knew I would have to specialize the superclass in order to be able to inherit it, but I really had no idea how to handle the overloaded operator call:
class SpecializedVector : public SimpleVector< SomeClass >
{
inline SomeClass& operator[]( unsigned long index ) {
Log( "Some information" );
return super.what the heck goes here?
}
};
C++ has no concept of Super, so I knew I'd have to use SimpleVector:: to get the proper method in the hierarchy, but what the heck method should get called? It turns out that you can do this by specializing the method call itself as well, like this:
return SimpleVector< SomeClass >::operator[]( index );
Not that I ever expect to have to do this again... but it was a really interesting lesson to understand how to pass-through overloaded operators in a template class.
setjmp/longjmp
I had heard of these functions, but never really understood how they were used. Mars was kind enough to give me a quick rundown of this very odd pair of C calls. Basically, you use setjmp and longjmp in conjunction with one another to implement a poorman's exception system in C. setjmp is an anchor that saves off state information into a buffer, and longjump calls it -- the real trickery comes from the return value of setjmp. The first time it is called, setjmp returns zero. However, if setjmp is executed by a call to longjmp, then setjmp returns whatever value is passed into longjmp! So, for a scary mixture of C and REALbasic code:
dim value as Integer
value = setjmp( buffer )
if value = 0 then
// Do some crazy code
longjmp( buffer, 100 )
elseif value = 100 then
// OMG! Ponies!
end if
The call to sejmp originally returns 0, so we get into the first if block. Then longjmp executes, which ends up *reexecuting* the call to setjmp's assignment. This time, value is 100, and we get into the second if block. Handy if you're stuck in C without exceptions. Not something you ever want to use from C++, or REALbasic!
Btw, I used the term "neat" in this posting's title very, very loosely. I doubt this information is of much use to anyone, even me. :-P
I used setjmp and longjmp to implement Objective-C exception-handling in REALbasic. This seems perilous.
setjmp / longjmp are intersting
Used them in C to create coroutines many many many years ago
But as Charles says "perilous"