Adventures in C++
On to the bonus round! As the ARM compiler has gotten better at correctly interpreting C++ code, many Brew programmers have decided to take that route for handset development. This makes it impossible, however, to have custom extensions since C++ compilers do not play nice with
vtables and the guts of the Brew extensions architecture. Let's take a look at how to make these two languages play nice with each other; along the way you'll make a basic C++ class and explore how to tie these divergent objects together.
Obviously, the Brew Extension is a C only affair. This forces you to 'wrap' all the C++ class methods in C style function calls. Let's see how this applies to the fictitious extension IReversal. IReversal.cpp contains a simple class with one function: Reverse. To get access to this class method from within the C extension, you're going to have to do some preprocessor wizardry. The following code shows the mess you'll have to declare in the header file (IReversal.h) to access the constructor, destructor, and method of the example C++ class:
#ifdef __cplusplus
extern "C" {
#endif
boolean IReversalpp_New(IShell *pShell, void **ppCppObj);
char * IReversalpp_Reverse(void *pObject, char *szString);
void IReversalpp_Delete(void * pObject);
#ifdef __cplusplus
}
#endif
What's going on in the above declaration? This file is going to be included in both a C and C++ compile which means it'll have to be palatable to both. If you're doing a C++ compile, the precompiler flag
__cplusplus will be true which extern the declarations as "C" style functions. This tells the C++ compiler to apply C style preprocessor and linking rules to them. When the compiler comes through
IReversal.h from your extension file
IReversal.c, these extern commands will be ignored and the functions will be linked normally as C functions. Here's the trick: the functions themselves have to be within a C++ file so they have access to the C++ lexicon of class interactions. By now, you probably have a pretty good idea what these C functions are going to look like. They're small, so take a look at them one at a time. Again, they’d be defined in
IReversal.cpp:
boolean IReversalpp_New(IShell *pShell, void **ppCppObj)
{
//Set up the new pointer and pass in the IShell object.
*ppCppObj = (void *) new IReversalpp(pShell);
if(*ppCppObj)
return TRUE;
else
return FALSE;
}
This function is really nothing more than a wrapper around the "new" function. It allocates and passes back a pointer to this new object. Remember that the C++ class must be stored by the C extension as a void pointer because a C compiler would have no idea what a "class" is. This is what the wrapper itself would look like:
char *IReversalpp_Reverse(void *pObject, char *szString)
{
IReversalpp pMe = (IReversalpp *) pObject;
return pMe->reverse(szString);
}
The above code simply casts the void pointer to your class object and calls into the reversal method. As for the actual implementation of the string reversal method, ask any CS 101 student to help you out with that one. Now, you can take a look at the final function in this simple example, the destructor:
void IReversalpp_Delete(void *pObject)
{
IReversalpp pMe = (IReversalpp *) pObject;
delete pMe;
}
Again, remember that your version of these should also be within the C++ file. It's what allows them to access C++ syntax while at the same time letting them link into the C code. Using the tricks I've outlined above, you should be on your way to writing an extension wrapping a C++ class. Armed with this knowledge, you could also write your extension in C++ (using any number of classes) and pass that functionally back through BREW's extension methodology.